From 5ffb1d3cfe174156a88528f6c2e23854f5363491 Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Fri, 11 Jul 2014 13:04:53 +0100
Subject: [PATCH] Issue #2216535 by jhodgdon, Berdir: Replace Node overview
 topic and Node API topic with Entity Hooks topic.

---
 .../Config/Entity/ConfigEntityStorage.php     |   2 +
 .../Entity/ContentEntityDatabaseStorage.php   |  12 +-
 .../Core/Entity/EntityStorageInterface.php    |   2 +
 .../Entity/EntityViewBuilderInterface.php     |   2 +
 core/modules/block/block.api.php              |   4 +
 core/modules/block/block.module               |   4 +-
 core/modules/book/book.module                 |  14 +-
 core/modules/comment/comment.api.php          | 166 -----
 core/modules/comment/comment.module           |   6 +-
 core/modules/field/field.api.php              |   2 +
 core/modules/file/file.api.php                | 128 +---
 core/modules/file/file.module                 |   6 +-
 .../file/tests/file_test/file_test.module     |   8 +-
 core/modules/forum/forum.module               |  16 +-
 core/modules/history/history.module           |   6 +-
 core/modules/image/image.module               |   2 +-
 core/modules/language/language.module         |   2 +-
 core/modules/menu_link/menu_link.api.php      | 125 +---
 core/modules/menu_ui/menu_ui.api.php          |  76 ---
 core/modules/menu_ui/menu_ui.module           |  27 +-
 core/modules/node/node.api.php                | 428 +-----------
 core/modules/node/node.module                 |  16 +-
 .../node/src/Tests/NodeCreationTest.php       |   3 +-
 .../src/Tests/NodeEntityViewModeAlterTest.php |   2 +-
 core/modules/node/src/Tests/NodeSaveTest.php  |  12 +-
 .../node_access_test/node_access_test.module  |   8 +-
 .../tests/modules/node_test/node_test.module  |  10 +-
 .../node_test_exception.module                |   2 +-
 core/modules/rdf/rdf.module                   |   2 +-
 core/modules/statistics/statistics.module     |   4 +-
 core/modules/system/core.api.php              |  95 ++-
 core/modules/system/entity.api.php            | 636 +++++++++++++++++-
 .../src/Tests/Entity/EntityCrudHookTest.php   |  14 +-
 core/modules/system/system.module             |   2 +-
 .../entity_crud_hook_test.module              |  98 +--
 .../tests/modules/menu_test/menu_test.module  |   6 +-
 core/modules/taxonomy/taxonomy.api.php        | 310 ---------
 core/modules/taxonomy/taxonomy.module         |   8 +-
 core/modules/toolbar/toolbar.module           |   6 +-
 core/modules/tour/tour.api.php                |  54 +-
 core/modules/tour/tour.module                 |   4 +-
 core/modules/tracker/tracker.module           |  12 +-
 core/modules/user/user.api.php                | 298 +-------
 core/modules/user/user.module                 |  20 +-
 44 files changed, 884 insertions(+), 1776 deletions(-)
 delete mode 100644 core/modules/menu_ui/menu_ui.api.php
 delete mode 100644 core/modules/taxonomy/taxonomy.api.php

diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php
index 57e4243d1b20..d0148904f18a 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php
@@ -35,6 +35,8 @@
  *   'article'. Entity IDs may contain dots/periods. The entire remaining string
  *   after the config_prefix in a config name forms the entity ID. Additional or
  *   custom suffixes are not possible.
+ *
+ * @ingroup entity_api
  */
 class ConfigEntityStorage extends EntityStorageBase implements ConfigEntityStorageInterface, ImportableEntityStorageInterface {
 
diff --git a/core/lib/Drupal/Core/Entity/ContentEntityDatabaseStorage.php b/core/lib/Drupal/Core/Entity/ContentEntityDatabaseStorage.php
index 2e2985710bcb..6f246f78ce1f 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityDatabaseStorage.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityDatabaseStorage.php
@@ -34,6 +34,8 @@
  * the defined base fields. Entity types can override
  * ContentEntityDatabaseStorage::getSchema() to customize the generated
  * schema; e.g., to add additional indexes.
+ *
+ * @ingroup entity_api
  */
 class ContentEntityDatabaseStorage extends ContentEntityStorageBase implements SqlEntityStorageInterface {
 
@@ -350,15 +352,7 @@ protected function doLoadMultiple(array $ids = NULL) {
   }
 
   /**
-   * Maps from storage records to entity objects.
-   *
-   * This will attach fields, if the entity is fieldable. It calls
-   * hook_entity_load() for modules which need to add data to all entities.
-   * It also calls hook_TYPE_load() on the loaded entities. For example
-   * hook_node_load() or hook_user_load(). If your hook_TYPE_load()
-   * expects special parameters apart from the queried entities, you can set
-   * $this->hookLoadArguments prior to calling the method.
-   * See Drupal\node\NodeStorage::attachLoad() for an example.
+   * Maps from storage records to entity objects, and attaches fields.
    *
    * @param array $records
    *   Associative array of query results, keyed on the entity ID.
diff --git a/core/lib/Drupal/Core/Entity/EntityStorageInterface.php b/core/lib/Drupal/Core/Entity/EntityStorageInterface.php
index e91f04c54f76..bb086e67336b 100644
--- a/core/lib/Drupal/Core/Entity/EntityStorageInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityStorageInterface.php
@@ -17,6 +17,8 @@
  * Most simple, SQL-based entity controllers will do better by extending
  * Drupal\Core\Entity\ContentEntityDatabaseStorage instead of implementing this
  * interface directly.
+ *
+ * @ingroup entity_api
  */
 interface EntityStorageInterface {
 
diff --git a/core/lib/Drupal/Core/Entity/EntityViewBuilderInterface.php b/core/lib/Drupal/Core/Entity/EntityViewBuilderInterface.php
index 32067a44de4f..89812fbef1ae 100644
--- a/core/lib/Drupal/Core/Entity/EntityViewBuilderInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityViewBuilderInterface.php
@@ -12,6 +12,8 @@
 
 /**
  * Defines a common interface for entity view controller classes.
+ *
+ * @ingroup entity_api
  */
 interface EntityViewBuilderInterface {
 
diff --git a/core/modules/block/block.api.php b/core/modules/block/block.api.php
index a0f79bffe722..f43d984f4cde 100644
--- a/core/modules/block/block.api.php
+++ b/core/modules/block/block.api.php
@@ -85,6 +85,8 @@
  *   The block plugin instance.
  *
  * @see hook_block_view_BASE_BLOCK_ID_alter()
+ * @see entity_crud
+ *
  * @ingroup block_api
  */
 function hook_block_view_alter(array &$build, \Drupal\block\BlockPluginInterface $block) {
@@ -113,6 +115,8 @@ function hook_block_view_alter(array &$build, \Drupal\block\BlockPluginInterface
  *   The block plugin instance.
  *
  * @see hook_block_view_alter()
+ * @see entity_crud
+ *
  * @ingroup block_api
  */
 function hook_block_view_BASE_BLOCK_ID_alter(array &$build, \Drupal\block\BlockPluginInterface $block) {
diff --git a/core/modules/block/block.module b/core/modules/block/block.module
index 4681b8a550b4..9a4118d82eee 100644
--- a/core/modules/block/block.module
+++ b/core/modules/block/block.module
@@ -298,7 +298,7 @@ function template_preprocess_block(&$variables) {
 }
 
 /**
- * Implements hook_user_role_delete().
+ * Implements hook_ENTITY_TYPE_delete() for user_role entities.
  *
  * Removes deleted role from blocks that use it.
  */
@@ -315,7 +315,7 @@ function block_user_role_delete($role) {
 }
 
 /**
- * Implements hook_menu_delete().
+ * Implements hook_ENTITY_TYPE_delete() for menu entities.
  */
 function block_menu_delete(Menu $menu) {
   if (!$menu->isSyncing()) {
diff --git a/core/modules/book/book.module b/core/modules/book/book.module
index 54aad063e3b8..ba00049b52a1 100644
--- a/core/modules/book/book.module
+++ b/core/modules/book/book.module
@@ -234,7 +234,7 @@ function book_form_update($form, $form_state) {
 }
 
 /**
- * Implements hook_node_load().
+ * Implements hook_ENTITY_TYPE_load() for node entities.
  */
 function book_node_load($nodes) {
   /** @var \Drupal\book\BookManagerInterface $book_manager */
@@ -248,7 +248,7 @@ function book_node_load($nodes) {
 }
 
 /**
- * Implements hook_node_view().
+ * Implements hook_ENTITY_TYPE_view() for node entities.
  */
 function book_node_view(array &$build, EntityInterface $node, EntityViewDisplayInterface $display, $view_mode) {
   if ($view_mode == 'full') {
@@ -268,7 +268,7 @@ function book_node_view(array &$build, EntityInterface $node, EntityViewDisplayI
 }
 
 /**
- * Implements hook_node_presave().
+ * Implements hook_ENTITY_TYPE_presave() for node entities.
  */
 function book_node_presave(EntityInterface $node) {
   // Make sure a new node gets a new menu link.
@@ -278,7 +278,7 @@ function book_node_presave(EntityInterface $node) {
 }
 
 /**
- * Implements hook_node_insert().
+ * Implements hook_ENTITY_TYPE_insert() for node entities.
  */
 function book_node_insert(EntityInterface $node) {
   /** @var \Drupal\book\BookManagerInterface $book_manager */
@@ -287,7 +287,7 @@ function book_node_insert(EntityInterface $node) {
 }
 
 /**
- * Implements hook_node_update().
+ * Implements hook_ENTITY_TYPE_update() for node entities.
  */
 function book_node_update(EntityInterface $node) {
   /** @var \Drupal\book\BookManagerInterface $book_manager */
@@ -296,7 +296,7 @@ function book_node_update(EntityInterface $node) {
 }
 
 /**
- * Implements hook_node_predelete().
+ * Implements hook_ENTITY_TYPE_predelete() for node entities.
  */
 function book_node_predelete(EntityInterface $node) {
   if (!empty($node->book['bid'])) {
@@ -555,7 +555,7 @@ function book_type_is_allowed($type) {
 }
 
 /**
- * Implements hook_node_type_update().
+ * Implements hook_ENTITY_TYPE_update() for node_type entities.
  *
  * Updates book.settings configuration object if the machine-readable name of a
  * node type is changed.
diff --git a/core/modules/comment/comment.api.php b/core/modules/comment/comment.api.php
index 176813b454cc..5430ee9f4acd 100644
--- a/core/modules/comment/comment.api.php
+++ b/core/modules/comment/comment.api.php
@@ -13,172 +13,6 @@
  * @{
  */
 
-/**
- * Act on a comment being inserted or updated.
- *
- * This hook is invoked from $comment->save() before the comment is saved to the
- * database.
- *
- * @param \Drupal\comment\Comment $comment
- *   The comment object.
- */
-function hook_comment_presave(Drupal\comment\Comment $comment) {
-  // Remove leading & trailing spaces from the comment subject.
-  $comment->setSubject(trim($comment->getSubject()));
-}
-
-/**
- * Respond to creation of a new comment.
- *
- * @param \Drupal\comment\Comment $comment
- *   The comment object.
- */
-function hook_comment_insert(Drupal\comment\Comment $comment) {
-  // Reindex the node when comments are added.
-  if ($comment->getCommentedEntityTypeId() == 'node') {
-    node_reindex_node_search($comment->getCommentedEntityId());
-  }
-}
-
-/**
- * Respond to updates to a comment.
- *
- * @param \Drupal\comment\Comment $comment
- *   The comment object.
- */
-function hook_comment_update(Drupal\comment\Comment $comment) {
-  // Reindex the node when comments are updated.
-  if ($comment->getCommentedEntityTypeId() == 'node') {
-    node_reindex_node_search($comment->getCommentedEntityId());
-  }
-}
-
-/**
- * Act on a newly created comment.
- *
- * This hook runs after a new comment object has just been instantiated. It can
- * be used to set initial values, e.g. to provide defaults.
- *
- * @param \Drupal\comment\Entity\Comment $comment
- *   The comment object.
- */
-function hook_comment_create(\Drupal\comment\Entity\Comment $comment) {
-  if (!isset($comment->foo)) {
-    $comment->foo = 'some_initial_value';
-  }
-}
-
-/**
- * Act on comments being loaded from the database.
- *
- * @param array $comments
- *  An array of comment objects indexed by cid.
- */
-function hook_comment_load(Drupal\comment\Comment $comments) {
-  $result = db_query('SELECT cid, foo FROM {mytable} WHERE cid IN (:cids)', array(':cids' => array_keys($comments)));
-  foreach ($result as $record) {
-    $comments[$record->cid]->foo = $record->foo;
-  }
-}
-
-/**
- * Act on a comment that is being assembled before rendering.
- *
- * @param array &$build
- *   A renderable array representing the comment content.
- * @param \Drupal\comment\Entity\Comment $comment $comment
- *   Passes in the comment the action is being performed on.
- * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
- *   The entity view display holding the display options configured for the
- *   comment components.
- * @param $view_mode
- *   View mode, e.g. 'full', 'teaser'...
- * @param $langcode
- *   The language code used for rendering.
- *
- * @see hook_entity_view()
- */
-function hook_comment_view(array &$build, \Drupal\comment\Entity\Comment $comment, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, $view_mode, $langcode) {
-  // Only do the extra work if the component is configured to be displayed.
-  // This assumes a 'mymodule_addition' extra field has been defined for the
-  // node type in hook_entity_extra_field_info().
-  if ($display->getComponent('mymodule_addition')) {
-    $build['mymodule_addition'] = array(
-      '#markup' => mymodule_addition($comment),
-      '#theme' => 'mymodule_my_additional_field',
-    );
-  }
-}
-
-/**
- * Alter the results of comment_view().
- *
- * This hook is called after the content has been assembled in a structured
- * array and may be used for doing processing which requires that the complete
- * comment content structure has been built.
- *
- * If the module wishes to act on the rendered HTML of the comment rather than
- * the structured content array, it may use this hook to add a #post_render
- * callback. Alternatively, it could also implement hook_preprocess_HOOK() for
- * comment.html.twig. See drupal_render() documentation for details.
- *
- * @param array &$build
- *   A renderable array representing the comment.
- * @param \Drupal\comment\Entity\Comment $comment
- *   The comment being rendered.
- * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
- *   The entity view display holding the display options configured for the
- *   comment components.
- *
- * @see comment_view()
- * @see hook_entity_view_alter()
- */
-function hook_comment_view_alter(array &$build, \Drupal\comment\Entity\Comment $comment, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display) {
-  // Check for the existence of a field added by another module.
-  if ($build['#view_mode'] == 'full' && isset($build['an_additional_field'])) {
-    // Change its weight.
-    $build['an_additional_field']['#weight'] = -10;
-  }
-
-  // Add a #post_render callback to act on the rendered HTML of the comment.
-  $build['#post_render'][] = 'my_module_comment_post_render';
-}
-
-/**
- * Act before comment deletion.
- *
- * This hook is invoked from entity_delete_multiple() before field values are
- * deleted and before the comment is actually removed from the database.
- *
- * @param \Drupal\comment\Comment $comment
- *   The comment object for the comment that is about to be deleted.
- *
- * @see hook_comment_delete()
- * @see entity_delete_multiple()
- */
-function hook_comment_predelete(Drupal\comment\Comment $comment) {
-  // Delete a record associated with the comment in a custom table.
-  db_delete('example_comment_table')
-    ->condition('cid', $comment->id())
-    ->execute();
-}
-
-/**
- * Respond to comment deletion.
- *
- * This hook is invoked from entity_delete_multiple() after field values are
- * deleted and after the comment has been removed from the database.
- *
- * @param \Drupal\comment\Comment $comment
- *   The comment object for the comment that has been deleted.
- *
- * @see hook_comment_predelete()
- * @see entity_delete_multiple()
- */
-function hook_comment_delete(Drupal\comment\Comment $comment) {
-  drupal_set_message(t('Comment: @subject has been deleted', array('@subject' => $comment->getSubject())));
-}
-
 /**
  * Alter the links of a comment.
  *
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index f567e88ceb06..401a3cf99b38 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -434,7 +434,7 @@ function comment_node_links_alter(array &$node_links, NodeInterface $node, array
 }
 
 /**
- * Implements hook_node_view_alter().
+ * Implements hook_ENTITY_TYPE_view_alter() for node entities.
  */
 function comment_node_view_alter(array &$build, EntityInterface $node, EntityViewDisplayInterface $display) {
   if (\Drupal::moduleHandler()->moduleExists('history')) {
@@ -639,7 +639,7 @@ function comment_view_multiple($comments, $view_mode = 'full', $langcode = NULL)
 }
 
 /**
- * Implements hook_form_FORM_ID_alter().
+ * Implements hook_form_FORM_ID_alter() for field_ui_field_overview_form.
  */
 function comment_form_field_ui_field_overview_form_alter(&$form, $form_state) {
   $request = \Drupal::request();
@@ -886,7 +886,7 @@ function comment_user_cancel($edit, $account, $method) {
 }
 
 /**
- * Implements hook_user_predelete().
+ * Implements hook_ENTITY_TYPE_predelete() for user entities.
  */
 function comment_user_predelete($account) {
   $entity_query = \Drupal::entityQuery('comment');
diff --git a/core/modules/field/field.api.php b/core/modules/field/field.api.php
index f364c517d237..fed48ca1065d 100644
--- a/core/modules/field/field.api.php
+++ b/core/modules/field/field.api.php
@@ -253,6 +253,8 @@ function hook_field_info_max_weight($entity_type, $bundle, $context, $context_mo
  *   The field as it will be post-update.
  * @param \Drupal\field\FieldConfigInterface $prior_field
  *   The field as it is pre-update.
+ *
+ * @see entity_crud
  */
 function hook_field_config_update_forbid(\Drupal\field\FieldConfigInterface $field, \Drupal\field\FieldConfigInterface $prior_field) {
   // A 'list' field stores integer keys mapped to display values. If
diff --git a/core/modules/file/file.api.php b/core/modules/file/file.api.php
index 898caa5d3cb0..6ec14c5590be 100644
--- a/core/modules/file/file.api.php
+++ b/core/modules/file/file.api.php
@@ -5,43 +5,10 @@
  * Hooks for file module.
  */
 
-
 /**
- * Act on a newly created file.
- *
- * This hook runs after a new file object has just been instantiated. It can be
- * used to set initial values, e.g. to provide defaults.
- *
- * @param \Drupal\file\Entity\File $file
- *   The file object.
+ * @addtogroup hooks
+ * @{
  */
-function hook_file_create(\Drupal\file\Entity\File $file) {
-  if (!isset($file->foo)) {
-    $file->foo = 'some_initial_value';
-  }
-}
-
-/**
- * Load additional information into file entities.
- *
- * file_load_multiple() calls this hook to allow modules to load
- * additional information into each file.
- *
- * @param $files
- *   An array of file entities, indexed by fid.
- *
- * @see file_load_multiple()
- * @see file_load()
- */
-function hook_file_load($files) {
-  // Add the upload specific data into the file entity.
-  $result = db_query('SELECT * FROM {upload} u WHERE u.fid IN (:fids)', array(':fids' => array_keys($files)))->fetchAll(PDO::FETCH_ASSOC);
-  foreach ($result as $record) {
-    foreach ($record as $key => $value) {
-      $files[$record['target_id']]->$key = $value;
-    }
-  }
-}
 
 /**
  * Check that files meet a given criteria.
@@ -70,58 +37,6 @@ function hook_file_validate(Drupal\file\FileInterface $file) {
   return $errors;
 }
 
-/**
- * Act on a file being inserted or updated.
- *
- * This hook is called when a file has been added to the database. The hook
- * doesn't distinguish between files created as a result of a copy or those
- * created by an upload.
- *
- * @param \Drupal\file\FileInterface $file
- *   The file entity that is about to be created or updated.
- */
-function hook_file_presave(Drupal\file\FileInterface $file) {
-  // Change the owner of the file.
-  $file->uid->value = 1;
-}
-
-/**
- * Respond to a file being added.
- *
- * This hook is called after a file has been added to the database. The hook
- * doesn't distinguish between files created as a result of a copy or those
- * created by an upload.
- *
- * @param \Drupal\file\FileInterface $file
- *   The file that has been added.
- */
-function hook_file_insert(Drupal\file\FileInterface $file) {
-  // Add a message to the log, if the file is a jpg
-  $validate = file_validate_extensions($file, 'jpg');
-  if (empty($validate)) {
-    \Drupal::logger('file')->notice('A jpg has been added.');
-  }
-}
-
-/**
- * Respond to a file being updated.
- *
- * This hook is called when an existing file is saved.
- *
- * @param \Drupal\file\FileInterface $file
- *   The file that has just been updated.
- */
-function hook_file_update(Drupal\file\FileInterface $file) {
-  // Make sure that the file name starts with the owner's user name.
-  if (strpos($file->getFilename(), $file->getOwner()->name) !== 0) {
-    $old_filename = $file->getFilename();
-    $file->setFilename($file->getOwner()->name . '_' . $file->getFilename());
-    $file->save();
-
-    \Drupal::logger('file')->notice('%source has been renamed to %destination', array('%source' => $old_filename, '%destination' => $file->getFilename()));
-  }
-}
-
 /**
  * Respond to a file that has been copied.
  *
@@ -162,41 +77,6 @@ function hook_file_move(Drupal\file\FileInterface $file, Drupal\file\FileInterfa
   }
 }
 
-/**
- * Act prior to file deletion.
- *
- * This hook is invoked when deleting a file before the file is removed from the
- * filesystem and before its records are removed from the database.
- *
- * @param \Drupal\file\FileInterface $file
- *   The file that is about to be deleted.
- *
- * @see hook_file_delete()
- * @see \Drupal\file\FileStorage::delete()
- * @see upload_file_delete()
- */
-function hook_file_predelete(Drupal\file\FileInterface $file) {
-  // Delete all information associated with the file.
-  db_delete('upload')->condition('fid', $file->id())->execute();
-}
-
-/**
- * Respond to file deletion.
- *
- * This hook is invoked after the file has been removed from
- * the filesystem and after its records have been removed from the database.
- *
- * @param \Drupal\file\FileInterface $file
- *   The file that has just been deleted.
- *
- * @see hook_file_predelete()
- * @see \Drupal\file\FileStorage::delete()
- */
-function hook_file_delete(Drupal\file\FileInterface $file) {
-  // Delete all information associated with the file.
-  db_delete('upload')->condition('fid', $file->id())->execute();
-}
-
 /**
  * Control download access to files.
  *
@@ -251,3 +131,7 @@ function hook_file_download_access_alter(&$grants, $context) {
     $grants = array('node' => $grants['node']);
   }
 }
+
+/**
+ * @} End of "addtogroup hooks".
+ */
diff --git a/core/modules/file/file.module b/core/modules/file/file.module
index 760a5832a57b..e78c6d642fb6 100644
--- a/core/modules/file/file.module
+++ b/core/modules/file/file.module
@@ -87,7 +87,7 @@ function file_element_info() {
  * @deprecated in Drupal 8.x, will be removed before Drupal 9.0.
  *   Use \Drupal\file\Entity\File::loadMultiple().
  *
- * @see hook_file_load()
+ * @see hook_ENTITY_TYPE_load()
  * @see file_load()
  * @see entity_load()
  * @see \Drupal\Core\Entity\Query\EntityQueryInterface
@@ -113,7 +113,7 @@ function file_load_multiple(array $fids = NULL, $reset = FALSE) {
  * @deprecated in Drupal 8.x, will be removed before Drupal 9.0.
  *   Use \Drupal\file\Entity\File::load().
  *
- * @see hook_file_load()
+ * @see hook_ENTITY_TYPE_load()
  * @see file_load_multiple()
  */
 function file_load($fid, $reset = FALSE) {
@@ -1002,7 +1002,7 @@ function file_progress_implementation() {
 }
 
 /**
- * Implements hook_file_predelete().
+ * Implements hook_ENTITY_TYPE_predelete() for file entities.
  */
 function file_file_predelete(File $file) {
   // TODO: Remove references to a file that is in-use.
diff --git a/core/modules/file/tests/file_test/file_test.module b/core/modules/file/tests/file_test/file_test.module
index 5fcd15fd9157..b1bdeb3cf33a 100644
--- a/core/modules/file/tests/file_test/file_test.module
+++ b/core/modules/file/tests/file_test/file_test.module
@@ -150,7 +150,7 @@ function file_test_set_return($op, $value) {
 }
 
 /**
- * Implements hook_file_load().
+ * Implements hook_ENTITY_TYPE_load() for file entities.
  */
 function file_test_file_load($files) {
   foreach ($files as $file) {
@@ -178,14 +178,14 @@ function file_test_file_download($uri) {
 }
 
 /**
- * Implements hook_file_insert().
+ * Implements hook_ENTITY_TYPE_insert() for file entities.
  */
 function file_test_file_insert(File $file) {
   _file_test_log_call('insert', array($file->id()));
 }
 
 /**
- * Implements hook_file_update().
+ * Implements hook_ENTITY_TYPE_update() for file entities.
  */
 function file_test_file_update(File $file) {
   _file_test_log_call('update', array($file->id()));
@@ -206,7 +206,7 @@ function file_test_file_move(File $file, File $source) {
 }
 
 /**
- * Implements hook_file_predelete().
+ * Implements hook_ENTITY_TYPE_predelete() for file entities.
  */
 function file_test_file_predelete(File $file) {
   _file_test_log_call('delete', array($file->id()));
diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module
index be7ef15b8199..23293fe2ea6b 100644
--- a/core/modules/forum/forum.module
+++ b/core/modules/forum/forum.module
@@ -233,7 +233,7 @@ function forum_node_validate(EntityInterface $node, $form, &$form_state) {
 }
 
 /**
- * Implements hook_node_presave().
+ * Implements hook_ENTITY_TYPE_presave() for node entities.
  *
  * Assigns the forum taxonomy when adding a topic from within a forum.
  */
@@ -256,7 +256,7 @@ function forum_node_presave(EntityInterface $node) {
 }
 
 /**
- * Implements hook_node_update().
+ * Implements hook_ENTITY_TYPE_update() for node entities.
  */
 function forum_node_update(EntityInterface $node) {
   if (\Drupal::service('forum_manager')->checkNodeType($node)) {
@@ -298,7 +298,7 @@ function forum_node_update(EntityInterface $node) {
 }
 
 /**
- * Implements hook_node_insert().
+ * Implements hook_ENTITY_TYPE_insert() for node entities.
  */
 function forum_node_insert(EntityInterface $node) {
   if (\Drupal::service('forum_manager')->checkNodeType($node)) {
@@ -316,7 +316,7 @@ function forum_node_insert(EntityInterface $node) {
 }
 
 /**
- * Implements hook_node_predelete().
+ * Implements hook_ENTITY_TYPE_predelete() for node entities.
  */
 function forum_node_predelete(EntityInterface $node) {
   if (\Drupal::service('forum_manager')->checkNodeType($node)) {
@@ -328,7 +328,7 @@ function forum_node_predelete(EntityInterface $node) {
 }
 
 /**
- * Implements hook_node_load().
+ * Implements hook_ENTITY_TYPE_load() for node entities.
  */
 function forum_node_load($nodes) {
   $node_vids = array();
@@ -358,7 +358,7 @@ function forum_permission() {
 }
 
 /**
- * Implements hook_comment_update().
+ * Implements hook_ENTITY_TYPE_update() for comment entities.
  */
 function forum_comment_update(CommentInterface $comment) {
   if ($comment->getCommentedEntityTypeId() == 'node') {
@@ -367,7 +367,7 @@ function forum_comment_update(CommentInterface $comment) {
 }
 
 /**
- * Implements hook_comment_insert().
+ * Implements hook_ENTITY_TYPE_insert() for comment entities.
  */
 function forum_comment_insert(CommentInterface $comment) {
   if ($comment->getCommentedEntityTypeId() == 'node') {
@@ -376,7 +376,7 @@ function forum_comment_insert(CommentInterface $comment) {
 }
 
 /**
- * Implements hook_comment_delete().
+ * Implements hook_ENTITY_TYPE_delete() for comment entities.
  */
 function forum_comment_delete(CommentInterface $comment) {
   if ($comment->getCommentedEntityTypeId() == 'node') {
diff --git a/core/modules/history/history.module b/core/modules/history/history.module
index 06e82d89e03f..f4c9742926b4 100644
--- a/core/modules/history/history.module
+++ b/core/modules/history/history.module
@@ -130,7 +130,7 @@ function history_cron() {
 }
 
 /**
- * Implements hook_node_view_alter().
+ * Implements hook_ENTITY_TYPE_view_alter() for node entities.
  */
 function history_node_view_alter(array &$build, EntityInterface $node, EntityViewDisplayInterface $display) {
   // Update the history table, stating that this user viewed this node.
@@ -148,7 +148,7 @@ function history_node_view_alter(array &$build, EntityInterface $node, EntityVie
 }
 
 /**
- * Implements hook_node_delete().
+ * Implements hook_ENTITY_TYPE_delete() for node entities.
  */
 function history_node_delete(EntityInterface $node) {
   db_delete('history')
@@ -170,7 +170,7 @@ function history_user_cancel($edit, $account, $method) {
 }
 
 /**
- * Implements hook_user_delete().
+ * Implements hook_ENTITY_TYPE_delete() for user entities.
  */
 function history_user_delete($account) {
   db_delete('history')
diff --git a/core/modules/image/image.module b/core/modules/image/image.module
index 406423628734..2ff2ecb7b143 100644
--- a/core/modules/image/image.module
+++ b/core/modules/image/image.module
@@ -228,7 +228,7 @@ function image_file_move(File $file, File $source) {
 }
 
 /**
- * Implements hook_file_predelete().
+ * Implements hook_ENTITY_TYPE_predelete() for file entities.
  */
 function image_file_predelete(File $file) {
   // Delete any image derivatives of this image.
diff --git a/core/modules/language/language.module b/core/modules/language/language.module
index e23d73f4c639..5ac331bf1c3e 100644
--- a/core/modules/language/language.module
+++ b/core/modules/language/language.module
@@ -347,7 +347,7 @@ function language_get_default_configuration_settings_key($entity_type, $bundle)
 }
 
 /**
- * Implements hook_node_type_update().
+ * Implements hook_ENTITY_TYPE_update() for node_type entities.
  */
 function language_node_type_update(NodeTypeInterface $type) {
   if ($type->original->id() != $type->id()) {
diff --git a/core/modules/menu_link/menu_link.api.php b/core/modules/menu_link/menu_link.api.php
index b4e88928b576..470243671874 100644
--- a/core/modules/menu_link/menu_link.api.php
+++ b/core/modules/menu_link/menu_link.api.php
@@ -17,7 +17,7 @@
  * translated; i.e., after the user access to the link's target page has
  * been checked. It is only invoked if $menu_link['options']['alter'] has been
  * set to a non-empty value (e.g. TRUE). This flag should be set using
- * hook_menu_link_presave().
+ * hook_ENTITY_TYPE_presave() for entity 'menu_link'.
  *
  * Implementations of this hook are able to alter any property of the menu link.
  * For example, this hook may be used to add a page-specific query string to all
@@ -37,129 +37,6 @@ function hook_translated_menu_link_alter(\Drupal\menu_link\Entity\MenuLink &$men
   }
 }
 
-/**
- * Alter menu links when loaded and before they are rendered.
- *
- * This hook is only invoked if $menu_link->options['alter'] has been set to a
- * non-empty value (e.g., TRUE). This flag should be set using
- * hook_menu_link_presave().
- * @ todo The paragraph above is lying! This hasn't been (re)implemented yet.
- *
- * Implementations of this hook are able to alter any property of the menu link.
- * For example, this hook may be used to add a page-specific query string to all
- * menu links, or hide a certain link by setting:
- * @code
- *   'hidden' => 1,
- * @endcode
- *
- * @param array $menu_links
- *   An array of menu link entities.
- *
- * @see hook_menu_link_presave()
- */
-function hook_menu_link_load($menu_links) {
-  foreach ($menu_links as $menu_link) {
-    if ($menu_link->href == 'devel/cache/clear') {
-      $menu_link->options['query'] = drupal_get_destination();
-    }
-  }
-}
-
-
-/**
- * Alter the data of a menu link entity before it is created or updated.
- *
- * @param \Drupal\menu_link\Entity\MenuLink $menu_link
- *   A menu link entity.
- *
- * @see hook_menu_link_load()
- */
-function hook_menu_link_presave(\Drupal\menu_link\Entity\MenuLink $menu_link) {
-  // Make all new admin links hidden (a.k.a disabled).
-  if (strpos($menu_link->link_path, 'admin') === 0 && $menu_link->isNew()) {
-    $menu_link->hidden = 1;
-  }
-  // Flag a link to be altered by hook_menu_link_load().
-  if ($menu_link->link_path == 'devel/cache/clear') {
-    $menu_link->options['alter'] = TRUE;
-  }
-  // Flag a menu link to be altered by hook_menu_link_load(), but only if it is
-  // derived from a menu router item; i.e., do not alter a custom menu link
-  // pointing to the same path that has been created by a user.
-  if ($menu_link->machine_name == 'user.page') {
-    $menu_link->options['alter'] = TRUE;
-  }
-}
-
-/**
- * Inform modules that a menu link has been created.
- *
- * This hook is used to notify modules that menu links have been
- * created. Contributed modules may use the information to perform
- * actions based on the information entered into the menu system.
- *
- * @param \Drupal\menu_link\Entity\MenuLink $menu_link
- *   A menu link entity.
- *
- * @see hook_menu_link_presave()
- * @see hook_menu_link_update()
- * @see hook_menu_link_delete()
- */
-function hook_menu_link_insert(\Drupal\menu_link\Entity\MenuLink $menu_link) {
-  // In our sample case, we track menu items as editing sections
-  // of the site. These are stored in our table as 'disabled' items.
-  $record['mlid'] = $menu_link->id();
-  $record['menu_name'] = $menu_link->menu_name;
-  $record['status'] = 0;
-  db_insert('menu_example')->fields($record)->execute();
-}
-
-/**
- * Inform modules that a menu link has been updated.
- *
- * This hook is used to notify modules that menu items have been
- * updated. Contributed modules may use the information to perform
- * actions based on the information entered into the menu system.
- *
- * @param \Drupal\menu_link\Entity\MenuLink $menu_link
- *   A menu link entity.
- *
- * @see hook_menu_link_presave()
- * @see hook_menu_link_insert()
- * @see hook_menu_link_delete()
- */
-function hook_menu_link_update(\Drupal\menu_link\Entity\MenuLink $menu_link) {
-  // If the parent menu has changed, update our record.
-  $menu_name = db_query("SELECT menu_name FROM {menu_example} WHERE mlid = :mlid", array(':mlid' => $menu_link->id()))->fetchField();
-  if ($menu_name != $menu_link->menu_name) {
-    db_update('menu_example')
-      ->fields(array('menu_name' => $menu_link->menu_name))
-      ->condition('mlid', $menu_link->id())
-      ->execute();
-  }
-}
-
-/**
- * Inform modules that a menu link has been deleted.
- *
- * This hook is used to notify modules that menu links have been
- * deleted. Contributed modules may use the information to perform
- * actions based on the information entered into the menu system.
- *
- * @param \Drupal\menu_link\Entity\MenuLink $menu_link
- *   A menu link entity.
- *
- * @see hook_menu_link_presave()
- * @see hook_menu_link_insert()
- * @see hook_menu_link_update()
- */
-function hook_menu_link_delete(\Drupal\menu_link\Entity\MenuLink $menu_link) {
-  // Delete the record from our table.
-  db_delete('menu_example')
-    ->condition('mlid', $menu_link->id())
-    ->execute();
-}
-
 /**
  * @} End of "addtogroup hooks".
  */
diff --git a/core/modules/menu_ui/menu_ui.api.php b/core/modules/menu_ui/menu_ui.api.php
deleted file mode 100644
index 04277153e167..000000000000
--- a/core/modules/menu_ui/menu_ui.api.php
+++ /dev/null
@@ -1,76 +0,0 @@
-<?php
-
-/**
- * @file
- * Hooks provided by the Menu UI module.
- */
-
-/**
- * @addtogroup hooks
- * @{
- */
-
-/**
- * Respond to a custom menu creation.
- *
- * This hook is used to notify modules that a custom menu has been created.
- * Contributed modules may use the information to perform actions based on the
- * information entered into the menu system.
- *
- * @param \Drupal\system\MenuInterface $menu
- *   The menu entity that was created.
- *
- * @see hook_menu_update()
- * @see hook_menu_delete()
- */
-function hook_menu_insert(\Drupal\system\MenuInterface $menu) {
-  drupal_set_message(t('You have just created a menu with a machine name %id.', array(
-    '%id' => $menu->id(),
-  )));
-}
-
-/**
- * Respond to a custom menu update.
- *
- * This hook is used to notify modules that a custom menu has been updated.
- * Contributed modules may use the information to perform actions based on the
- * information entered into the menu system.
- *
- * @param \Drupal\system\MenuInterface $menu
- *   The menu entity that was updated.
- *
- * @see hook_menu_insert()
- * @see hook_menu_delete()
- */
-function hook_menu_update(\Drupal\system\MenuInterface $menu) {
-  if ($type->original->id() != $type->id()) {
-    drupal_set_message(t('You have just changed the machine name of the menu %old_id to %id.', array(
-      '%old_id' => $menu->original->id(),
-      '%id' => $menu->id(),
-    )));
-  }
-}
-
-/**
- * Respond to a custom menu deletion.
- *
- * This hook is used to notify modules that a custom menu along with all links
- * contained in it (if any) has been deleted. Contributed modules may use the
- * information to perform actions based on the information entered into the menu
- * system.
- *
- * @param \Drupal\system\MenuInterface $menu
- *   The menu entity that was deleted.
- *
- * @see hook_menu_insert()
- * @see hook_menu_update()
- */
-function hook_menu_delete(\Drupal\system\MenuInterface $menu) {
-  drupal_set_message(t('You have just deleted the menu with machine name %id.', array(
-    '%id' => $menu->id(),
-  )));
-}
-
-/**
- * @} End of "addtogroup hooks".
- */
diff --git a/core/modules/menu_ui/menu_ui.module b/core/modules/menu_ui/menu_ui.module
index 5e2f5bcf6e14..70b5b5944e54 100644
--- a/core/modules/menu_ui/menu_ui.module
+++ b/core/modules/menu_ui/menu_ui.module
@@ -5,10 +5,7 @@
  * Allows administrators to customize the site's navigation menus.
  *
  * A menu (in this context) is a hierarchical collection of links, generally
- * used for navigation. This is not to be confused with the
- * @link menu Menu system @endlink of menu.inc and hook_menu(), which defines
- * page routing requests for Drupal, and also allows the defined page routing
- * URLs to be added to the main site navigation menu.
+ * used for navigation.
  */
 
 use Drupal\Core\Entity\EntityInterface;
@@ -114,7 +111,7 @@ function menu_ui_theme() {
 }
 
 /**
- * Implements hook_menu_insert()
+ * Implements hook_ENTITY_TYPE_insert( for menu entities.
  */
 function menu_ui_menu_insert(Menu $menu) {
   menu_cache_clear_all();
@@ -142,7 +139,7 @@ function menu_ui_menu_insert(Menu $menu) {
 }
 
 /**
- * Implements hook_menu_update().
+ * Implements hook_ENTITY_TYPE_update() for menu entities.
  */
 function menu_ui_menu_update(Menu $menu) {
   menu_cache_clear_all();
@@ -153,7 +150,7 @@ function menu_ui_menu_update(Menu $menu) {
 }
 
 /**
- * Implements hook_menu_predelete().
+ * Implements hook_ENTITY_TYPE_predelete() for menu entities.
  */
 function menu_ui_menu_predelete(Menu $menu) {
   // Delete all links from the menu.
@@ -174,7 +171,7 @@ function menu_ui_menu_predelete(Menu $menu) {
 }
 
 /**
- * Implements hook_menu_delete().
+ * Implements hook_ENTITY_TYPE_delete() for menu entities.
  */
 function menu_ui_menu_delete(Menu $menu) {
   menu_cache_clear_all();
@@ -297,21 +294,21 @@ function menu_ui_block_view_system_menu_block_alter(array &$build, BlockPluginIn
 }
 
 /**
- * Implements hook_node_insert().
+ * Implements hook_ENTITY_TYPE_insert() for node entities.
  */
 function menu_ui_node_insert(EntityInterface $node) {
   menu_ui_node_save($node);
 }
 
 /**
- * Implements hook_node_update().
+ * Implements hook_ENTITY_TYPE_update() for node entities.
  */
 function menu_ui_node_update(EntityInterface $node) {
   menu_ui_node_save($node);
 }
 
 /**
- * Implements hook_node_type_insert().
+ * Implements hook_ENTITY_TYPE_insert() for node_type entities.
  */
 function menu_ui_node_type_insert(NodeTypeInterface $type) {
   if ($type->isSyncing()) {
@@ -324,7 +321,7 @@ function menu_ui_node_type_insert(NodeTypeInterface $type) {
 }
 
 /**
- * Implements hook_node_type_delete().
+ * Implements hook_ENTITY_TYPE_delete() for node_type entities.
  */
 function menu_ui_node_type_delete(NodeTypeInterface $type) {
   if ($type->isSyncing()) {
@@ -334,7 +331,7 @@ function menu_ui_node_type_delete(NodeTypeInterface $type) {
 }
 
 /**
- * Helper for hook_node_insert() and hook_node_update().
+ * Helper for hook_ENTITY_TYPE_insert() and hook_ENTITY_TYPE_update() for nodes.
  */
 function menu_ui_node_save(EntityInterface $node) {
   if (isset($node->menu)) {
@@ -363,7 +360,7 @@ function menu_ui_node_save(EntityInterface $node) {
 }
 
 /**
- * Implements hook_node_predelete().
+ * Implements hook_ENTITY_TYPE_predelete() for node entities.
  */
 function menu_ui_node_predelete(EntityInterface $node) {
   // Delete all Menu UI module links that point to this node.
@@ -442,7 +439,7 @@ function _menu_ui_parent_depth_limit($item) {
 }
 
 /**
- * Implements hook_form_BASE_FORM_ID_alter().
+ * Implements hook_form_BASE_FORM_ID_alter() for node_form.
  *
  * Adds menu item fields to the node form.
  *
diff --git a/core/modules/node/node.api.php b/core/modules/node/node.api.php
index 35ac5332874f..247c239ca4ec 100644
--- a/core/modules/node/node.api.php
+++ b/core/modules/node/node.api.php
@@ -6,105 +6,7 @@
 
 /**
  * @file
- * Hooks provided by the Node module.
- */
-
-/**
- * @defgroup node_api_hooks Node API Hooks
- * @{
- * Functions to define and modify content types.
- *
- * Each content type is maintained by a primary module, which is either
- * node.module (for content types created in the user interface) or the module
- * that defines the content type by providing configuration file.
- *
- * During node operations (create, insert, update, view, delete, etc.), there
- * are several sets of hooks that get invoked to allow modules to modify the
- * base node operation:
- * - All-module hooks: This set of hooks is invoked on all implementing modules,
- *   to allow other modules to modify what the primary node module is doing. For
- *   example, hook_node_insert() is invoked on all modules when creating a forum
- *   node.
- * - Field hooks: Hooks related to the fields attached to the node. These are
- *   invoked from the field operations functions described below, and can be
- *   either field-type-specific or all-module hooks.
- * - Entity hooks: Generic hooks for "entity" operations. These are always
- *   invoked on all modules.
- *
- * Here is a list of the node and entity hooks that are invoked, and other
- * steps that take place during node operations:
- * - Instantiating a new node:
- *   - hook_node_create() (all)
- *   - hook_entity_create() (all)
- * - Creating a new node (calling $node->save() on a new node):
- *   - hook_node_presave() (all)
- *   - hook_entity_presave() (all)
- *   - Node and revision records are written to the database
- *   - hook_node_insert() (all)
- *   - hook_entity_insert() (all)
- *   - hook_node_access_records() (all)
- *   - hook_node_access_records_alter() (all)
- * - Updating an existing node (calling $node->save() on an existing node):
- *   - hook_node_presave() (all)
- *   - hook_entity_presave() (all)
- *   - Node and revision records are written to the database
- *   - hook_node_update() (all)
- *   - hook_entity_update() (all)
- *   - hook_node_access_records() (all)
- *   - hook_node_access_records_alter() (all)
- * - Loading a node (calling node_load(), node_load_multiple(), entity_load(),
- *   or entity_load_multiple() with $entity_type of 'node'):
- *   - Node and revision information is read from database.
- *   - hook_entity_load() (all)
- *   - hook_node_load() (all)
- * - Viewing a single node (calling node_view() - note that the input to
- *   node_view() is a loaded node, so the Loading steps above are already done):
- *   - hook_entity_prepare_view() (all)
- *   - hook_entity_display_build_alter() (all)
- *   - hook_node_view() (all)
- *   - hook_entity_view() (all)
- *   - hook_node_view_alter() (all)
- *   - hook_entity_view_alter() (all)
- * - Viewing multiple nodes (calling node_view_multiple() - note that the input
- *   to node_view_multiple() is a set of loaded nodes, so the Loading steps
- *   above are already done):
- *   - hook_entity_prepare_view() (all)
- *   - hook_entity_display_build_alter() (all)
- *   - hook_node_view() (all)
- *   - hook_entity_view() (all)
- *   - hook_node_view_alter() (all)
- *   - hook_entity_view_alter() (all)
- * - Deleting a node (calling $node->delete() or entity_delete_multiple()):
- *   - Node is loaded (see Loading section above)
- *   - hook_node_predelete() (all)
- *   - hook_entity_predelete() (all)
- *   - Node and revision information are deleted from database
- *   - hook_node_delete() (all)
- *   - hook_entity_delete() (all)
- * - Deleting a node revision (calling node_revision_delete()):
- *   - Node is loaded (see Loading section above)
- *   - Revision information is deleted from database
- *   - hook_node_revision_delete() (all)
- * - Preparing a node for editing (calling node_form() - note that if it is an
- *   existing node, it will already be loaded; see the Loading section above):
- *   - hook_node_prepare_form() (all)
- *   - hook_entity_prepare_form() (all)
- *   - @todo hook for EntityFormDisplay::buildForm()
- * - Validating a node during editing form submit (calling
- *   node_form_validate()):
- *   - hook_node_validate() (all)
- * - Searching (using the 'node_search' plugin):
- *   - hook_ranking() (all)
- *   - Query is executed to find matching nodes
- *   - Resulting node is loaded (see Loading section above)
- *   - Resulting node is prepared for viewing (see Viewing a single node above)
- *   - comment_node_update_index() is called (this adds "N comments" text)
- *   - hook_node_search_result() (all)
- * - Search indexing (calling updateIndex() on the 'node_search' plugin):
- *   - Node is loaded (see Loading section above)
- *   - Node is prepared for viewing (see Viewing a single node above)
- *   - hook_node_update_index() (all)
- * @}
+ * Hooks specific to the Node module.
  */
 
 /**
@@ -380,147 +282,6 @@ function hook_node_grants_alter(&$grants, \Drupal\Core\Session\AccountInterface
   }
 }
 
-/**
- * Act before node deletion.
- *
- * This hook is invoked from entity_delete_multiple() before
- * hook_entity_predelete() is called and field values are deleted, and before
- * the node is removed from the node table in the database.
- *
- * @param \Drupal\node\NodeInterface $node
- *   The node that is about to be deleted.
- *
- * @see hook_node_predelete()
- * @see entity_delete_multiple()
- * @ingroup node_api_hooks
- */
-function hook_node_predelete(\Drupal\node\NodeInterface $node) {
-  db_delete('mytable')
-    ->condition('nid', $node->id())
-    ->execute();
-}
-
-/**
- * Respond to node deletion.
- *
- * This hook is invoked from entity_delete_multiple() after field values are
- * deleted and after the node has been removed from the database.
- *
- * @param \Drupal\node\NodeInterface $node
- *   The node that has been deleted.
- *
- * @see hook_node_predelete()
- * @see entity_delete_multiple()
- * @ingroup node_api_hooks
- */
-function hook_node_delete(\Drupal\node\NodeInterface $node) {
-  drupal_set_message(t('Node: @title has been deleted', array('@title' => $node->label())));
-}
-
-/**
- * Respond to deletion of a node revision.
- *
- * This hook is invoked from node_revision_delete() after the revision has been
- * removed from the node_revision table, and before field values are deleted.
- *
- * @param \Drupal\node\NodeInterface $node
- *   The node revision (node object) that is being deleted.
- *
- * @ingroup node_api_hooks
- */
-function hook_node_revision_delete(\Drupal\node\NodeInterface $node) {
-  db_delete('mytable')
-    ->condition('vid', $node->getRevisionId())
-    ->execute();
-}
-
-/**
- * Respond to creation of a new node.
- *
- * This hook is invoked from $node->save() after the database query that will
- * insert the node into the node table is scheduled for execution, and after
- * field values are saved.
- *
- * Note that when this hook is invoked, the changes have not yet been written to
- * the database, because a database transaction is still in progress. The
- * transaction is not finalized until the save operation is entirely completed
- * and $node->save() goes out of scope. You should not rely on data in the
- * database at this time as it is not updated yet. You should also note that any
- * write/update database queries executed from this hook are also not committed
- * immediately. Check $node->save() and db_transaction() for more info.
- *
- * @param \Drupal\node\NodeInterface $node
- *   The node that is being created.
- *
- * @ingroup node_api_hooks
- */
-function hook_node_insert(\Drupal\node\NodeInterface $node) {
-  db_insert('mytable')
-    ->fields(array(
-      'nid' => $node->id(),
-      'extra' => $node->extra,
-    ))
-    ->execute();
-}
-
-/**
- * Act on a newly created node.
- *
- * This hook runs after a new node object has just been instantiated. It can be
- * used to set initial values, e.g. to provide defaults.
- *
- * @param \Drupal\node\NodeInterface $node
- *   The node object.
- *
- * @ingroup node_api_hooks
- */
-function hook_node_create(\Drupal\node\NodeInterface $node) {
-  if (!isset($node->foo)) {
-    $node->foo = 'some_initial_value';
-  }
-}
-
-/**
- * Act on arbitrary nodes being loaded from the database.
- *
- * This hook should be used to add information that is not in the node or node
- * revisions table, not to replace information that is in these tables (which
- * could interfere with the entity cache). For performance reasons, information
- * for all available nodes should be loaded in a single query where possible.
- *
- * This hook is invoked during node loading, which is handled by entity_load(),
- * via classes Drupal\node\NodeStorage and
- * Drupal\Core\Entity\ContentEntityDatabaseStorage. After the node information
- * and field values are read from the database or the entity cache,
- * hook_entity_load() is invoked on all implementing modules, and finally
- * hook_node_load() is invoked on all implementing modules.
- *
- * @param $nodes
- *   An array of the nodes being loaded, keyed by nid.
- *
- * For a detailed usage example, see nodeapi_example.module.
- *
- * @ingroup node_api_hooks
- */
-function hook_node_load($nodes) {
-  // Decide whether any of $types are relevant to our purposes.
-  $types_we_want_to_process = \Drupal::config('my_types')->get('types');
-  $nids = array();
-  foreach ($nodes as $node) {
-    if (in_array($node->bundle(), $types_we_want_to_process)) {
-      $nids = $node->id();
-    }
-  }
-  if ($nids) {
-    // Gather our extra data for each of these nodes.
-    $result = db_query('SELECT nid, foo FROM {mytable} WHERE nid IN(:nids)', array(':nids' => $nids));
-    // Add our extra data to the node objects.
-    foreach ($result as $record) {
-      $nodes[$record->nid]->foo = $record->foo;
-    }
-  }
-}
-
 /**
  * Controls access to a node.
  *
@@ -588,27 +349,6 @@ function hook_node_access(\Drupal\node\NodeInterface $node, $op, $account, $lang
   return NODE_ACCESS_IGNORE;
 }
 
-
-/**
- * Act on a node object about to be shown on the add/edit form.
- *
- * This hook is invoked from NodeForm::prepareEntity().
- *
- * @param \Drupal\node\NodeInterface $node
- *   The node that is about to be shown on the form.
- * @param $operation
- *   The current operation.
- * @param array $form_state
- *   An associative array containing the current state of the form.
- *
- * @ingroup node_api_hooks
- */
-function hook_node_prepare_form(\Drupal\node\NodeInterface $node, $operation, array &$form_state) {
-  if (!isset($node->my_rating)) {
-    $node->my_rating = \Drupal::config("my_rating_{$node->bundle()}")->get('enabled');
-  }
-}
-
 /**
  * Act on a node being displayed as a search result.
  *
@@ -629,60 +369,13 @@ function hook_node_prepare_form(\Drupal\node\NodeInterface $node, $operation, ar
  * @see template_preprocess_search_result()
  * @see search-result.html.twig
  *
- * @ingroup node_api_hooks
+ * @ingroup entity_crud
  */
 function hook_node_search_result(\Drupal\node\NodeInterface $node, $langcode) {
   $rating = db_query('SELECT SUM(points) FROM {my_rating} WHERE nid = :nid', array('nid' => $node->id()))->fetchField();
   return array('rating' => format_plural($rating, '1 point', '@count points'));
 }
 
-/**
- * Act on a node being inserted or updated.
- *
- * This hook is invoked from $node->save() before the node is saved to the
- * database.
- *
- * @param \Drupal\node\NodeInterface $node
- *   The node that is being inserted or updated.
- *
- * @ingroup node_api_hooks
- */
-function hook_node_presave(\Drupal\node\NodeInterface $node) {
-  if ($node->id() && $node->moderate) {
-    // Reset votes when node is updated:
-    $node->score = 0;
-    $node->users = '';
-    $node->votes = 0;
-  }
-}
-
-/**
- * Respond to updates to a node.
- *
- * This hook is invoked from $node->save() after the database query that will
- * update node in the node table is scheduled for execution, and after field
- * values are saved.
- *
- * Note that when this hook is invoked, the changes have not yet been written to
- * the database, because a database transaction is still in progress. The
- * transaction is not finalized until the save operation is entirely completed
- * and $node->save() goes out of scope. You should not rely on data in the
- * database at this time as it is not updated yet. You should also note that any
- * write/update database queries executed from this hook are also not committed
- * immediately. Check $node->save() and db_transaction() for more info.
- *
- * @param \Drupal\node\NodeInterface $node
- *   The node that is being updated.
- *
- * @ingroup node_api_hooks
- */
-function hook_node_update(\Drupal\node\NodeInterface $node) {
-  db_update('mytable')
-    ->fields(array('extra' => $node->extra))
-    ->condition('nid', $node->id())
-    ->execute();
-}
-
 /**
  * Act on a node being indexed for searching.
  *
@@ -697,7 +390,7 @@ function hook_node_update(\Drupal\node\NodeInterface $node) {
  * @return string
  *   Additional node information to be indexed.
  *
- * @ingroup node_api_hooks
+ * @ingroup entity_crud
  */
 function hook_node_update_index(\Drupal\node\NodeInterface $node, $langcode) {
   $text = '';
@@ -729,7 +422,7 @@ function hook_node_update_index(\Drupal\node\NodeInterface $node, $langcode) {
  * @param $form_state
  *   The form state array.
  *
- * @ingroup node_api_hooks
+ * @ingroup entity_crud
  */
 function hook_node_validate(\Drupal\node\NodeInterface $node, $form, &$form_state) {
   if (isset($node->end) && isset($node->start)) {
@@ -756,7 +449,7 @@ function hook_node_validate(\Drupal\node\NodeInterface $node, $form, &$form_stat
  * @param $form_state
  *   The form state array.
  *
- * @ingroup node_api_hooks
+ * @ingroup entity_crud
  */
 function hook_node_submit(\Drupal\node\NodeInterface $node, $form, &$form_state) {
   // Decompose the selected menu parent option into 'menu_name' and 'plid', if
@@ -766,82 +459,6 @@ function hook_node_submit(\Drupal\node\NodeInterface $node, $form, &$form_state)
   }
 }
 
-/**
- * Act on a node that is being assembled before rendering.
- *
- * The module may add elements to a node's renderable array array prior to
- * rendering.
- *
- * When $view_mode is 'rss', modules can also add extra RSS elements and
- * namespaces to $node->rss_elements and $node->rss_namespaces respectively for
- * the RSS item generated for this node.
- * For details on how this is used, see node_feed().
- *
- * @param array &$build
- *   A renderable array representing the node content.
- * @param \Drupal\node\NodeInterface $node
- *   The node that is being assembled for rendering.
- * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
- *   The entity view display holding the display options configured for the node
- *   components.
- * @param string $view_mode
- *   The $view_mode parameter from node_view().
- * @param string $langcode
- *   The language code used for rendering.
- *
- * @see forum_node_view()
- * @see hook_entity_view()
- *
- * @ingroup node_api_hooks
- */
-function hook_node_view(array &$build, \Drupal\node\NodeInterface $node, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, $view_mode, $langcode) {
-  // Only do the extra work if the component is configured to be displayed.
-  // This assumes a 'mymodule_addition' extra field has been defined for the
-  // node type in hook_entity_extra_field_info().
-  if ($display->getComponent('mymodule_addition')) {
-    $build['mymodule_addition'] = array(
-      '#markup' => mymodule_addition($node),
-      '#theme' => 'mymodule_my_additional_field',
-    );
-  }
-}
-
-/**
- * Alter the results of node_view().
- *
- * This hook is called after the content has been assembled in a structured
- * array and may be used for doing processing which requires that the complete
- * node content structure has been built.
- *
- * If the module wishes to act on the rendered HTML of the node rather than the
- * structured content array, it may use this hook to add a #post_render
- * callback.  Alternatively, it could also implement hook_preprocess_HOOK() for
- * node.html.twig. See drupal_render() and _theme() documentation respectively
- * for details.
- *
- * @param &$build
- *   A renderable array representing the node content.
- * @param \Drupal\node\NodeInterface $node
- *   The node being rendered.
- * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
- *   The entity view display holding the display options configured for the node
- *   components.
- *
- * @see node_view()
- * @see hook_entity_view_alter()
- *
- * @ingroup node_api_hooks
- */
-function hook_node_view_alter(array &$build, \Drupal\node\NodeInterface $node, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display) {
-  if ($build['#view_mode'] == 'full' && isset($build['an_additional_field'])) {
-    // Change its weight.
-    $build['an_additional_field']['#weight'] = -10;
-  }
-
-  // Add a #post_render callback to act on the rendered HTML of the node.
-  $build['#post_render'][] = 'my_module_node_post_render';
-}
-
 /**
  * Provide additional methods of scoring for core search results for nodes.
  *
@@ -883,7 +500,7 @@ function hook_node_view_alter(array &$build, \Drupal\node\NodeInterface $node, \
  *   - arguments: (optional) If any arguments are required for the score, they
  *     can be specified in an array here.
  *
- * @ingroup node_api_hooks
+ * @ingroup entity_crud
  */
 function hook_ranking() {
   // If voting is disabled, we can avoid returning the array, no hard feelings.
@@ -904,38 +521,6 @@ function hook_ranking() {
   }
 }
 
-/**
- * Respond to node type creation.
- *
- * @param \Drupal\node\NodeTypeInterface $type
- *   The node type entity that was created.
- */
-function hook_node_type_insert(\Drupal\node\NodeTypeInterface $type) {
-  drupal_set_message(t('You have just created a content type with a machine name %type.', array('%type' => $type->id())));
-}
-
-/**
- * Respond to node type updates.
- *
- * @param \Drupal\node\NodeTypeInterface $type
- *   The node type entity that was updated.
- */
-function hook_node_type_update(\Drupal\node\NodeTypeInterface $type) {
-  if ($type->original->id() != $type->id()) {
-    drupal_set_message(t('You have just changed the machine name of a content type from %old_type to %type.', array('%old_type' => $type->original->id(), '%type' => $type->id())));
-  }
-}
-
-/**
- * Respond to node type deletion.
- *
- * @param \Drupal\node\NodeTypeInterface $type
- *   The node type entity that was deleted.
- */
-function hook_node_type_delete(\Drupal\node\NodeTypeInterface $type) {
-  drupal_set_message(t('You have just deleted a content type with the machine name %type.', array('%type' => $type->id())));
-}
-
 /**
  * Alter the links of a node.
  *
@@ -951,6 +536,7 @@ function hook_node_type_delete(\Drupal\node\NodeTypeInterface $type) {
  *
  * @see \Drupal\node\NodeViewBuilder::renderLinks()
  * @see \Drupal\node\NodeViewBuilder::buildLinks()
+ * @see entity_crud
  */
 function hook_node_links_alter(array &$links, NodeInterface $entity, array &$context) {
   $links['mymodule'] = array(
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 44ac84908bd2..a34ca8225c08 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -785,7 +785,7 @@ function node_user_cancel($edit, $account, $method) {
 }
 
 /**
- * Implements hook_user_predelete().
+ * Implements hook_ENTITY_TYPE_predelete() for user entities.
  */
 function node_user_predelete($account) {
   // Delete nodes (current revisions).
@@ -1134,10 +1134,12 @@ function node_form_system_themes_admin_form_submit($form, &$form_state) {
  * default home page at path 'node', an RSS feed, a recent content block, etc.),
  * the process above is followed except that hook_node_access() is not called on
  * each node for performance reasons and for proper functioning of the pager
- * system. When adding a node listing to your module, be sure to use a dynamic
- * entity query and add a tag of "node_access". This will allow modules dealing
+ * system. When adding a node listing to your module, be sure to use an entity
+ * query, which will add a tag of "node_access". This will allow modules dealing
  * with node access to ensure only nodes to which the user has access are
- * retrieved, through the use of hook_query_TAG_alter().
+ * retrieved, through the use of hook_query_TAG_alter(). See the
+ * @link entity_api Entity API topic @endlink for more information on entity
+ * queries.
  *
  * Note: Even a single module returning NODE_ACCESS_DENY from hook_node_access()
  * will block access to the node. Therefore, implementers should take care to
@@ -1628,7 +1630,7 @@ function node_reindex_node_search($nid) {
 }
 
 /**
- * Implements hook_comment_insert().
+ * Implements hook_ENTITY_TYPE_insert() for comment entities.
  */
 function node_comment_insert($comment) {
   // Reindex the node when comments are added.
@@ -1638,7 +1640,7 @@ function node_comment_insert($comment) {
 }
 
 /**
- * Implements hook_comment_update().
+ * Implements hook_ENTITY_TYPE_update() for comment entities.
  */
 function node_comment_update($comment) {
   // Reindex the node when comments are changed.
@@ -1648,7 +1650,7 @@ function node_comment_update($comment) {
 }
 
 /**
- * Implements hook_comment_delete().
+ * Implements hook_ENTITY_TYPE_delete() for comment entities.
  */
 function node_comment_delete($comment) {
   // Reindex the node when comments are deleted.
diff --git a/core/modules/node/src/Tests/NodeCreationTest.php b/core/modules/node/src/Tests/NodeCreationTest.php
index 7ea8b4d2329b..a305ca54393d 100644
--- a/core/modules/node/src/Tests/NodeCreationTest.php
+++ b/core/modules/node/src/Tests/NodeCreationTest.php
@@ -20,7 +20,8 @@ class NodeCreationTest extends NodeTestBase {
   /**
    * Modules to enable.
    *
-   * Enable dummy module that implements hook_node_insert() for exceptions.
+   * Enable dummy module that implements hook_ENTITY_TYPE_insert() for
+   * exceptions (function node_test_exception_node_insert() ).
    *
    * @var array
    */
diff --git a/core/modules/node/src/Tests/NodeEntityViewModeAlterTest.php b/core/modules/node/src/Tests/NodeEntityViewModeAlterTest.php
index 4f6345c4df81..a979ef8ae004 100644
--- a/core/modules/node/src/Tests/NodeEntityViewModeAlterTest.php
+++ b/core/modules/node/src/Tests/NodeEntityViewModeAlterTest.php
@@ -15,7 +15,7 @@
 class NodeEntityViewModeAlterTest extends NodeTestBase {
 
   /**
-   * Enable dummy module that implements hook_node_view().
+   * Enable dummy module that implements hook_ENTITY_TYPE_view() for nodes.
    */
   public static $modules = array('node_test');
 
diff --git a/core/modules/node/src/Tests/NodeSaveTest.php b/core/modules/node/src/Tests/NodeSaveTest.php
index eaafdd5dd086..75e3651261a4 100644
--- a/core/modules/node/src/Tests/NodeSaveTest.php
+++ b/core/modules/node/src/Tests/NodeSaveTest.php
@@ -89,7 +89,7 @@ function testTimestamps() {
     $node = $this->drupalGetNodeByTitle($edit['title'], TRUE);
     $this->assertEqual($node->getCreatedTime(), $created, 'Updating a node preserves "created" timestamp.');
 
-    // Programmatically set the timestamps using hook_node_presave.
+    // Programmatically set the timestamps using hook_ENTITY_TYPE_presave().
     $node->title = 'testing_node_presave';
 
     $node->save();
@@ -124,8 +124,8 @@ function testTimestamps() {
   /**
    * Tests node presave and static node load cache.
    *
-   * This test determines changes in hook_node_presave() and verifies that the
-   * static node load cache is cleared upon save.
+   * This test determines changes in hook_ENTITY_TYPE_presave() and verifies
+   * that the static node load cache is cleared upon save.
    */
   function testDeterminingChanges() {
     // Initial creation.
@@ -156,9 +156,9 @@ function testDeterminingChanges() {
   /**
    * Tests saving a node on node insert.
    *
-   * This test ensures that a node has been fully saved when hook_node_insert()
-   * is invoked, so that the node can be saved again in a hook implementation
-   * without errors.
+   * This test ensures that a node has been fully saved when
+   * hook_ENTITY_TYPE_insert() is invoked, so that the node can be saved again
+   * in a hook implementation without errors.
    *
    * @see node_test_node_insert()
    */
diff --git a/core/modules/node/tests/modules/node_access_test/node_access_test.module b/core/modules/node/tests/modules/node_access_test/node_access_test.module
index df3abbf7f2a2..696f29ef9bbf 100644
--- a/core/modules/node/tests/modules/node_access_test/node_access_test.module
+++ b/core/modules/node/tests/modules/node_access_test/node_access_test.module
@@ -157,7 +157,7 @@ function node_access_test_form_node_form_alter(&$form, $form_state) {
 }
 
 /**
- * Implements hook_node_load().
+ * Implements hook_ENTITY_TYPE_load() for node entities.
  */
 function node_access_test_node_load($nodes) {
   $result = db_query('SELECT nid, private FROM {node_access_test} WHERE nid IN(:nids)', array(':nids' => array_keys($nodes)));
@@ -167,21 +167,21 @@ function node_access_test_node_load($nodes) {
 }
 
 /**
- * Implements hook_node_predelete().
+ * Implements hook_ENTITY_TYPE_predelete() for node entities.
  */
 function node_access_test_node_predelete(NodeInterface $node) {
   db_delete('node_access_test')->condition('nid', $node->id())->execute();
 }
 
 /**
- * Implements hook_node_insert().
+ * Implements hook_ENTITY_TYPE_insert() for node entities.
  */
 function node_access_test_node_insert(NodeInterface $node) {
   _node_access_test_node_write($node);
 }
 
 /**
- * Implements hook_nodeapi_update().
+ * Implements hook_ENTITY_TYPE_update() for node entities.
  */
 function node_access_test_node_update(NodeInterface $node) {
   _node_access_test_node_write($node);
diff --git a/core/modules/node/tests/modules/node_test/node_test.module b/core/modules/node/tests/modules/node_test/node_test.module
index 58624c372bb8..ed9af445f452 100644
--- a/core/modules/node/tests/modules/node_test/node_test.module
+++ b/core/modules/node/tests/modules/node_test/node_test.module
@@ -13,7 +13,7 @@
 use Drupal\node\NodeInterface;
 
 /**
- * Implements hook_node_view().
+ * Implements hook_ENTITY_TYPE_view() for node entities.
  */
 function node_test_node_view(array &$build, NodeInterface $node, EntityViewDisplayInterface $display, $view_mode) {
   if ($view_mode == 'rss') {
@@ -39,7 +39,7 @@ function node_test_node_view(array &$build, NodeInterface $node, EntityViewDispl
 }
 
 /**
- * Implements hook_ENTITY_TYPE_build_defaults_alter().
+ * Implements hook_ENTITY_TYPE_build_defaults_alter() for node entities.
  */
 function node_test_node_build_defaults_alter(array &$build, NodeInterface &$node, $view_mode = 'full', $langcode = NULL) {
   if ($view_mode == 'rss') {
@@ -119,7 +119,7 @@ function node_test_node_grants_alter(&$grants, AccountInterface $account, $op) {
 }
 
 /**
- * Implements hook_node_presave().
+ * Implements hook_ENTITY_TYPE_presave() for node entities.
  */
 function node_test_node_presave(NodeInterface $node) {
   if ($node->getTitle() == 'testing_node_presave') {
@@ -137,7 +137,7 @@ function node_test_node_presave(NodeInterface $node) {
 }
 
 /**
- * Implements hook_node_update().
+ * Implements hook_ENTITY_TYPE_update() for node entities.
  */
 function node_test_node_update(NodeInterface $node) {
   // Determine changes on update.
@@ -160,7 +160,7 @@ function node_test_entity_view_mode_alter(&$view_mode, Drupal\Core\Entity\Entity
 }
 
 /**
- * Implements hook_node_insert().
+ * Implements hook_ENTITY_TYPE_insert() for node entities.
  *
  * This tests saving a node on node insert.
  *
diff --git a/core/modules/node/tests/modules/node_test_exception/node_test_exception.module b/core/modules/node/tests/modules/node_test_exception/node_test_exception.module
index b696ca48a011..b016fe871b1e 100644
--- a/core/modules/node/tests/modules/node_test_exception/node_test_exception.module
+++ b/core/modules/node/tests/modules/node_test_exception/node_test_exception.module
@@ -8,7 +8,7 @@
 use Drupal\node\NodeInterface;
 
 /**
- * Implements hook_node_insert().
+ * Implements hook_ENTITY_TYPE_insert() for node entities.
  */
 function node_test_exception_node_insert(NodeInterface $node) {
   if ($node->getTitle() == 'testing_transaction_exception') {
diff --git a/core/modules/rdf/rdf.module b/core/modules/rdf/rdf.module
index 7bfb13c0957a..1221147a7420 100644
--- a/core/modules/rdf/rdf.module
+++ b/core/modules/rdf/rdf.module
@@ -224,7 +224,7 @@ function rdf_entity_prepare_view($entity_type, array $entities, array $displays)
 }
 
 /**
- * Implements hook_comment_load().
+ * Implements hook_ENTITY_TYPE_load() for comment entities.
  */
 function rdf_comment_load($comments) {
   foreach ($comments as $comment) {
diff --git a/core/modules/statistics/statistics.module b/core/modules/statistics/statistics.module
index bce72c749e93..fbcf70267cb1 100644
--- a/core/modules/statistics/statistics.module
+++ b/core/modules/statistics/statistics.module
@@ -48,7 +48,7 @@ function statistics_permission() {
 }
 
 /**
- * Implements hook_node_view().
+ * Implements hook_ENTITY_TYPE_view() for node entities.
  */
 function statistics_node_view(array &$build, EntityInterface $node, EntityViewDisplayInterface $display, $view_mode) {
   if (!$node->isNew() && $view_mode == 'full' && node_is_page($node) && empty($node->in_preview)) {
@@ -195,7 +195,7 @@ function _statistics_format_item($title, $path) {
 }
 
 /**
- * Implements hook_node_predelete().
+ * Implements hook_ENTITY_TYPE_predelete() for node entities.
  */
 function statistics_node_predelete(EntityInterface $node) {
   // clean up statistics table when node is deleted
diff --git a/core/modules/system/core.api.php b/core/modules/system/core.api.php
index 7a212cfa002d..ecbb006cead1 100644
--- a/core/modules/system/core.api.php
+++ b/core/modules/system/core.api.php
@@ -32,16 +32,16 @@
  * @section store_retrieve Storing and retrieving data
  *
  * - @link entity_api Entities @endlink
+ * - @link field Fields @endlink
  * - @link config_api Configuration API @endlink
  * - @link state_api State API @endlink
- * - @link field Fields @endlink
- * - @link node_overview Node system @endlink
  * - @link views_overview Views @endlink
  * - @link database Database abstraction layer @endlink
  *
  * @section other_essentials Other essential APIs
  *
  * - @link plugin_api Plugins @endlink
+ * - @link container Services and the Dependency Injection Container @endlink
  * - @link i18n Internationalization @endlink
  * - @link cache Caching @endlink
  * - @link utility Utility classes and functions @endlink
@@ -53,7 +53,6 @@
  *
  * - @link batch Batch API @endlink
  * - @link queue Queue API @endlink
- * - @link container Services and the Dependency Injection Container @endlink
  * - @link typed_data Typed Data @endlink
  * - @link testing Automated tests @endlink
  * - @link third_party Integrating third-party applications @endlink
@@ -391,12 +390,15 @@
  *     entities), to provide an administrative overview for your entities.
  *   - add and edit forms, or default form: Define a class (or two) that
  *     extend(s) \Drupal\Core\Entity\EntityForm to provide add and edit forms
- *     for your entities.
+ *     for your entities. For content entities, base class
+ *     \Drupal\Core\Entity\ContentEntityForm is a better starting point.
  *   - delete form: Define a class that extends
  *     \Drupal\Core\Entity\EntityConfirmFormBase to provide a delete
  *     confirmation form for your entities.
- *   - view_buider: For content entities, define a class that extends
- *     \Drupal\Core\Entity\EntityViewBuilder, to display a single entity.
+ *   - view_builder: For content entities and config entities that need to be
+ *     viewed, define a class that implements
+ *     \Drupal\Core\Entity\EntityViewBuilderInterface (usually extending
+ *     \Drupal\Core\Entity\EntityViewBuilder), to display a single entity.
  *   - translation: For translatable content entities (if the 'translatable'
  *     annotation has value TRUE), define a class that extends
  *     \Drupal\content_translation\ContentTranslationHandler, to translate
@@ -405,7 +407,14 @@
  *   - access: If your configuration entity has complex permissions, you might
  *     need an access controller, implementing
  *     \Drupal\Core\Entity\EntityAccessControllerInterface, but most entities
- *     can just use the 'admin_permission' annotation instead.
+ *     can just use the 'admin_permission' annotation instead. Note that if you
+ *     are creating your own access controller, you should override the
+ *     checkAccess() and checkCreateAccess() methods, not access().
+ *   - storage: A class implementing
+ *     \Drupal\Core\Entity\EntityStorageInterface. If not specified, content
+ *     entities will use \Drupal\Core\Entity\ContentEntityDatabaseStorage, and
+ *     config entities will use \Drupal\Core\Config\Entity\ConfigEntityStorage.
+ *     You can extend one of these classes to provide custom behavior.
  * - For content entities, the annotation will refer to a number of database
  *   tables and their fields. These annotation properties, such as 'base_table',
  *   'data_table', 'entity_keys', etc., are documented on
@@ -436,7 +445,9 @@
  *   'bundle_entity_type' annotation on the entity type class. For example, for
  *   the Node entity, the bundle class is \Drupal\node\Entity\NodeType, whose
  *   machine name is 'node_type'. This is the annotation value for
- *  'bundle_entity_type' on the \Drupal\node\Entity\Node class.
+ *   'bundle_entity_type' on the \Drupal\node\Entity\Node class. Also, the
+ *   bundle config entity type annotation must have a 'bundle_of' entry,
+ *   giving the machine name of the entity type it is acting as a bundle for.
  * - Additional annotations can be seen on entity class examples such as
  *   \Drupal\node\Entity\Node (content) and \Drupal\user\Entity\Role
  *   (configuration). These annotations are documented on
@@ -473,7 +484,25 @@
  *       "default" = "Drupal\block\BlockForm",
  *   @endcode
  *
- * @section load_query Loading and querying entities
+ * @section bundle Defining a content entity bundle
+ * For entity types that use bundles, such as Node (bundles are content types)
+ * and Taxonomy (bundles are vocabularies), modules and install profiles can
+ * define bundles by supplying default configuration in their config/install
+ * directories. (See the @link config_api Configuration API topic @endlink for
+ * general information about configuration.)
+ *
+ * There are several good examples of this in Drupal Core:
+ * - The Forum module defines a content type in node.type.forum.yml and a
+ *   vocabulary in taxonomy.vocabulary.forums.yml
+ * - The Book module defines a content type in node.type.book.yml
+ * - The Standard install profile defines Page and Article content types in
+ *   node.type.page.yml and node.type.article.yml, a Tags vocabulary in
+ *   taxonomy.vocabulary.tags.yml, and a Node comment type in
+ *   comment.type.comment.yml. This profile's configuration is especially
+ *   instructive, because it also adds several fields to the Article type, and
+ *   it sets up view and form display modes for the node types.
+ *
+ * @section load_query Loading, querying, and rendering entities
  * To load entities, use the entity storage manager, which is an object
  * implementing \Drupal\Core\Entity\EntityStorageInterface that you can
  * retrieve with:
@@ -523,6 +552,24 @@
  * $files = $storage->loadMultiple($fids);
  * @endcode
  *
+ * The normal way of viewing entities is by using a route, as described in the
+ * sections above. If for some reason you need to render an entity in code in a
+ * particular view mode, you can use an entity view builder, which is an object
+ * implementing \Drupal\Core\Entity\EntityViewBuilderInterface that you can
+ * retrieve with:
+ * @code
+ * $view_builder = \Drupal::entityManager()->getViewBuilder('your_entity_type');
+ * // Or if you have a $container variable:
+ * $view_builder = $container->get('entity.manager')->getViewBuilder('your_entity_type');
+ * @endcode
+ * Then, to build and render the entity:
+ * @code
+ * // You can omit the language ID if the default language is being used.
+ * $build = $view_builder->view($entity, 'view_mode_name', $language->id);
+ * // $build is a render array.
+ * $rendered = drupal_render($build);
+ * @endcode
+ *
  * @section sec_access Access checking on entities
  * Entity types define their access permission scheme in their annotation.
  * Access permissions can be quite complex, so you should not assume any
@@ -536,25 +583,21 @@
  * The interface related to access checking in entities and fields is
  * \Drupal\Core\Access\AccessibleInterface.
  *
- * @see i18n
- * @}
- */
-
-/**
- * @defgroup node_overview Nodes Overview
- * @{
- * Overview of how to interact with the Node system
+ * The default entity access controller invokes two hooks while checking
+ * access on a single entity: hook_entity_access() is invoked first, and
+ * then hook_ENTITY_TYPE_access() (where ENTITY_TYPE is the machine name
+ * of the entity type). If no module returns a TRUE or FALSE value from
+ * either of these hooks, then the entity's default access checking takes
+ * place. For create operations (creating a new entity), the hooks that
+ * are invoked are hook_entity_create_access() and
+ * hook_ENTITY_TYPE_create_access() instead.
  *
- * @todo write this
+ * The Node entity type has a complex system for determining access, which
+ * developers can interact with. This is described in the
+ * @link node_access Node access topic. @endlink
  *
- * Additional documentation paragraphs need to be written, and functions,
- * classes, and interfaces need to be added to this topic. This topic should
- * describe node access, the node classes/interfaces, and the node hooks that a
- * developer would need to know about, at a high level, and link to more
- * detailed information.
- *
- * @see node_access
- * @see node_api_hooks
+ * @see i18n
+ * @see entity_crud
  * @}
  */
 
diff --git a/core/modules/system/entity.api.php b/core/modules/system/entity.api.php
index da1d53ec22d5..1bab346dd20c 100644
--- a/core/modules/system/entity.api.php
+++ b/core/modules/system/entity.api.php
@@ -10,6 +10,231 @@
 use Drupal\Core\Field\FieldDefinition;
 use Drupal\Core\Render\Element;
 
+/**
+ * @defgroup entity_crud Entity CRUD, editing, and view hooks
+ * @{
+ * Hooks used in various entity operations.
+ *
+ * Entity create, read, update, and delete (CRUD) operations are performed by
+ * entity storage classes; see the
+ * @link entity_api Entity API topic @endlink for more information. Most
+ * entities use or extend the default classes:
+ * \Drupal\Core\Entity\ContentEntityDatabaseStorage for content entities, and
+ * \Drupal\Core\Config\Entity\ConfigEntityStorage for configuration entities.
+ * For these entities, there is a set of hooks that is invoked for each
+ * CRUD operation, which module developers can implement to affect these
+ * operations; these hooks are actually invoked from methods on
+ * \Drupal\Core\Entity\EntityStorageBase.
+ *
+ * For content entities, viewing and rendering are handled by a view builder
+ * class; see the @link entity_api Entity API topic @endlink for more
+ * information. Most view builders extend or use the default class
+ * \Drupal\Core\Entity\EntityViewBuilder.
+ *
+ * Entity editing (including adding new entities) is handled by entity form
+ * classes; see the @link entity_api Entity API topic @endlink for more
+ * information. Most entity editing forms extend base classes
+ * \Drupal\Core\Entity\EntityForm or \Drupal\Core\Entity\ContentEntityForm.
+ * Note that many other operations, such as confirming deletion of entities,
+ * also use entity form classes.
+ *
+ * This topic lists all of the entity CRUD and view operations, and the hooks
+ * and other operations that are invoked (in order) for each operation. Some
+ * notes:
+ * - Whenever an entity hook is invoked, there is both a type-specific entity
+ *   hook, and a generic entity hook. For instance, during a create operation on
+ *   a node, first hook_node_create() and then hook_entity_create() would be
+ *   invoked.
+ * - The entity-type-specific hooks are represented in the list below as
+ *   hook_ENTITY_TYPE_... (hook_ENTITY_TYPE_create() in this example). To
+ *   implement one of these hooks for an entity whose machine name is "foo",
+ *   define a function called mymodule_foo_create(), for instance. Also note
+ *   that the entity or array of entities that are passed into a specific-type
+ *   hook are of the specific entity class, not the generic Entity class, so in
+ *   your implementation, you can make the $entity argument something like $node
+ *   and give it a specific type hint (which should normally be to the specific
+ *   interface, such as \Drupal\Node\NodeInterface for nodes).
+ * - $storage in the code examples is assumed to be an entity storage
+ *   class. See the @link entity_api Entity API topic @endlink for
+ *   information on how to instantiate the correct storage class for an
+ *   entity type.
+ * - $view_builder in the code examples is assumed to be an entity view builder
+ *   class. See the @link entity_api Entity API topic @endlink for
+ *   information on how to instantiate the correct view builder class for
+ *   an entity type.
+ * - During many operations, static methods are called on the entity class,
+ *   which implements \Drupal\Entity\EntityInterface.
+ *
+ * @section create Create operations
+ * To create an entity:
+ * @code
+ * $entity = $storage->create();
+ *
+ * // Add code here to set properties on the entity.
+ *
+ * // Until you call save(), the entity is just in memory.
+ * $entity->save();
+ * @endcode
+ * There is also a shortcut method on entity classes, which creates an entity
+ * with an array of provided property values: \Drupal\Core\Entity::create().
+ *
+ * Hooks invoked during the create operation:
+ * - hook_ENTITY_TYPE_create()
+ * - hook_entity_create()
+ *
+ * See @ref save below for the save portion of the operation.
+ *
+ * @section load Read/Load operations
+ * To load (read) a single entity:
+ * @code
+ * $entity = $storage->load($id);
+ * @endcode
+ * To load multiple entities:
+ * @code
+ * $entities = $storage->loadMultiple($ids);
+ * @endcode
+ * Since load() calls loadMultiple(), these are really the same operation.
+ * Here is the order of hooks and other operations that take place during
+ * entity loading:
+ * - Entity is loaded from storage.
+ * - postLoad() is called on the entity class, passing in all of the loaded
+ *   entities.
+ * - hook_entity_load()
+ * - hook_ENTITY_TYPE_load()
+ *
+ * When an entity is loaded, normally the default entity revision is loaded.
+ * It is also possible to load a different revision, for entities that support
+ * revisions, with this code:
+ * @code
+ * $entity = $storage->loadRevision($revision_id);
+ * @endcode
+ * This involves the same hooks and operations as regular entity loading.
+ *
+ * @section save Save operations
+ * To update an existing entity, you will need to load it, change properties,
+ * and then save; as described above, when creating a new entity, you will also
+ * need to save it. Here is the order of hooks and other events that happen
+ * during an entity save:
+ * - preSave() is called on the entity object, and field objects.
+ * - hook_ENTITY_TYPE_presave()
+ * - hook_entity_presave()
+ * - Entity is saved to storage.
+ * - For updates on content entities, if there is a translation added that
+ *   was not previously present:
+ *   - hook_ENTITY_TYPE_translation_insert()
+ *   - hook_entity_translation_insert()
+ * - For updates on content entities, if there was a translation removed:
+ *   - hook_ENTITY_TYPE_translation_delete()
+ *   - hook_entity_translation_delete()
+ * - postSave() is called on the entity object.
+ * - hook_ENTITY_TYPE_insert() (new) or hook_ENTITY_TYPE_update() (update)
+ * - hook_entity_insert() (new) or hook_entity_update() (update)
+ *
+ * Some specific entity types invoke hooks during preSave() or postSave()
+ * operations. Examples:
+ * - Field configuration preSave(): hook_field_config_update_forbid()
+ * - Node postSave(): hook_node_access_records() and
+ *   hook_node_access_records_alter()
+ * - Config entities that are acting as entity bundles, in postSave():
+ *   hook_entity_bundle_create() or hook_entity_bundle_rename() as appropriate
+ * - Comment: hook_comment_publish() and hook_comment_unpublish() as
+ *   appropriate.
+ *
+ * @section edit Editing operations
+ * When an entity's add/edit form is used to add or edit an entity, there
+ * are several hooks that are invoked:
+ * - hook_entity_prepare_form()
+ * - hook_ENTITY_TYPE_prepare_form()
+ * - hook_entity_form_display_alter() (for content entities only)
+ *
+ * Some specific entity types have additional hooks that are run during
+ * various steps in the process:
+ * - Node entities: hook_node_validate() and hook_submit().
+ *
+ * @section delete Delete operations
+ * To delete one or more entities, load them and then delete them:
+ * @code
+ * $entities = $storage->loadMultiple($ids);
+ * $storage->delete($entities);
+ * @endcode
+ *
+ * During the delete operation, the following hooks and other events happen:
+ * - preDelete() is called on the entity class.
+ * - hook_ENTITY_TYPE_predelete()
+ * - hook_entity_predelete()
+ * - Entity and field information is removed from storage.
+ * - postDelete() is called on the entity class.
+ * - hook_ENTITY_TYPE_delete()
+ * - hook_entity_delete()
+ *
+ * Some specific entity types invoke hooks during the delete process. Examples:
+ * - Entity bundle postDelete(): hook_entity_bundle_delete()
+ *
+ * Individual revisions of an entity can also be deleted:
+ * @code
+ * $storage->deleteRevision($revision_id);
+ * @endcode
+ * This operation invokes the following operations and hooks:
+ * - Revision is loaded (see @ref load above).
+ * - Revision and field information is removed from the database.
+ * - hook_ENTITY_TYPE_revision_delete()
+ * - hook_entity_revision_delete()
+ *
+ * @section view View/render operations
+ * To make a render array for a loaded entity:
+ * @code
+ * // You can omit the language ID if the default language is being used.
+ * $build = $view_builder->view($entity, 'view_mode_name', $language->id);
+ * @endcode
+ * You can also use the viewMultiple() method to view multiple entities.
+ *
+ * Hooks invoked during the operation of building a render array:
+ * - hook_entity_view_mode_alter()
+ * - hook_ENTITY_TYPE_build_defaults_alter()
+ * - hook_entity_build_defaults_alter()
+ *
+ * View builders for some types override these hooks, notably:
+ * - The Tour view builder does not invoke any hooks.
+ * - The Block view builder invokes hook_block_view_alter() and
+ *   hook_block_view_BASE_BLOCK_ID_alter(). Note that in other view builders,
+ *   the view alter hooks are run later in the process.
+ *
+ * During the rendering operation, the default entity viewer runs the following
+ * hooks and operations in the pre-render step:
+ * - hook_entity_view_display_alter()
+ * - hook_entity_prepare_view()
+ * - Entity fields are loaded, and render arrays are built for them using
+ *   their formatters.
+ * - hook_entity_display_build_alter()
+ * - hook_ENTITY_TYPE_view()
+ * - hook_entity_view()
+ * - hook_ENTITY_TYPE_view_alter()
+ * - hook_entity_view_alter()
+ *
+ * Some specific builders have specific hooks:
+ * - The Node view builder invokes hook_node_links_alter().
+ * - The Comment view builder invokes hook_comment_links_alter().
+ *
+ * After this point in rendering, the theme system takes over. See the
+ * @link theme_render Theme system and render API topic @endlink for more
+ * information.
+ *
+ * @section misc Other entity hooks
+ * Some types of entities invoke hooks for specific operations:
+ * - Searching nodes:
+ *   - hook_ranking()
+ *   - Query is executed to find matching nodes
+ *   - Resulting node is loaded
+ *   - Node render array is built
+ *   - comment_node_update_index() is called (this adds "N comments" text)
+ *   - hook_node_search_result()
+ * - Search indexing nodes:
+ *   - Node is loaded
+ *   - Node render array is built
+ *   - hook_node_update_index()
+ * @}
+ */
+
 /**
  * @addtogroup hooks
  * @{
@@ -32,6 +257,10 @@
  *   deny access.
  *
  * @see \Drupal\Core\Entity\EntityAccessController
+ * @see hook_entity_create_access()
+ * @see hook_ENTITY_TYPE_access()
+ *
+ * @ingroup entity_api
  */
 function hook_entity_access(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Session\AccountInterface $account, $langcode) {
   return NULL;
@@ -54,6 +283,10 @@ function hook_entity_access(\Drupal\Core\Entity\EntityInterface $entity, $operat
  *   deny access.
  *
  * @see \Drupal\Core\Entity\EntityAccessController
+ * @see hook_ENTITY_TYPE_create_access()
+ * @see hook_entity_access()
+ *
+ * @ingroup entity_api
  */
 function hook_ENTITY_TYPE_access(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Session\AccountInterface $account, $langcode) {
   return NULL;
@@ -72,6 +305,10 @@ function hook_ENTITY_TYPE_access(\Drupal\Core\Entity\EntityInterface $entity, $o
  *   deny access.
  *
  * @see \Drupal\Core\Entity\EntityAccessController
+ * @see hook_entity_access()
+ * @see hook_ENTITY_TYPE_create_access()
+ *
+ * @ingroup entity_api
  */
 function hook_entity_create_access(\Drupal\Core\Session\AccountInterface $account, $langcode) {
   return NULL;
@@ -90,6 +327,10 @@ function hook_entity_create_access(\Drupal\Core\Session\AccountInterface $accoun
  *   deny access.
  *
  * @see \Drupal\Core\Entity\EntityAccessController
+ * @see hook_ENTITY_TYPE_access()
+ * @see hook_entity_create_access()
+ *
+ * @ingroup entity_api
  */
 function hook_ENTITY_TYPE_create_access(\Drupal\Core\Session\AccountInterface $account, $langcode) {
   return NULL;
@@ -198,6 +439,8 @@ function hook_entity_bundle_info_alter(&$bundles) {
  *   The type of $entity; e.g. 'node' or 'user'.
  * @param string $bundle
  *   The name of the bundle.
+ *
+ * @see entity_crud
  */
 function hook_entity_bundle_create($entity_type_id, $bundle) {
   // When a new bundle is created, the menu needs to be rebuilt to add the
@@ -216,6 +459,8 @@ function hook_entity_bundle_create($entity_type_id, $bundle) {
  *   The previous name of the bundle.
  * @param string $bundle_new
  *   The new name of the bundle.
+ *
+ * @see entity_crud
  */
 function hook_entity_bundle_rename($entity_type_id, $bundle_old, $bundle_new) {
   // Update the settings associated with the bundle in my_module.settings.
@@ -237,6 +482,8 @@ function hook_entity_bundle_rename($entity_type_id, $bundle_old, $bundle_new) {
  *   The type of entity; for example, 'node' or 'user'.
  * @param string $bundle
  *   The bundle that was just deleted.
+ *
+ * @ingroup entity_crud
  */
 function hook_entity_bundle_delete($entity_type_id, $bundle) {
   // Remove the settings associated with the bundle in my_module.settings.
@@ -256,6 +503,9 @@ function hook_entity_bundle_delete($entity_type_id, $bundle) {
  *
  * @param \Drupal\Core\Entity\EntityInterface $entity
  *   The entity object.
+ *
+ * @ingroup entity_crud
+ * @see hook_ENTITY_TYPE_create()
  */
 function hook_entity_create(\Drupal\Core\Entity\EntityInterface $entity) {
   if ($entity instanceof ContentEntityInterface && !$entity->foo->value) {
@@ -263,6 +513,24 @@ function hook_entity_create(\Drupal\Core\Entity\EntityInterface $entity) {
   }
 }
 
+/**
+ * Act on a newly created entity of a specific type.
+ *
+ * This hook runs after a new entity object has just been instantiated. It can
+ * be used to set initial values, e.g. to provide defaults.
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $entity
+ *   The entity object.
+ *
+ * @ingroup entity_crud
+ * @see hook_entity_create()
+ */
+function hook_ENTITY_TYPE_create(\Drupal\Core\Entity\EntityInterface $entity) {
+  if (!$entity->foo->value) {
+    $entity->foo->value = 'some_initial_value';
+  }
+}
+
 /**
  * Act on entities when loaded.
  *
@@ -273,6 +541,9 @@ function hook_entity_create(\Drupal\Core\Entity\EntityInterface $entity) {
  *   The entities keyed by entity ID.
  * @param string $entity_type_id
  *   The type of entities being loaded (i.e. node, user, comment).
+ *
+ * @ingroup entity_crud
+ * @see hook_ENTITY_TYPE_load()
  */
 function hook_entity_load($entities, $entity_type_id) {
   foreach ($entities as $entity) {
@@ -281,13 +552,50 @@ function hook_entity_load($entities, $entity_type_id) {
 }
 
 /**
- * Act on an entity before it is about to be created or updated.
+ * Act on entities of a specific type when loaded.
+ *
+ * @param array $entities
+ *   The entities keyed by entity ID.
+ *
+ * @ingroup entity_crud
+ * @see hook_entity_load()
+ */
+function hook_ENTITY_TYPE_load($entities) {
+  foreach ($entities as $entity) {
+    $entity->foo = mymodule_add_something($entity);
+  }
+}
+
+/**
+ * Act on an entity before it is created or updated.
  *
  * @param \Drupal\Core\Entity\EntityInterface $entity
  *   The entity object.
+ *
+ * @ingroup entity_crud
+ * @see hook_ENTITY_TYPE_presave()
  */
 function hook_entity_presave(Drupal\Core\Entity\EntityInterface $entity) {
-  $entity->changed = REQUEST_TIME;
+ if ($entity instanceof ContentEntityInterface && $entity->isTranslatable()) {
+   $attributes = \Drupal::request()->attributes;
+   \Drupal::service('content_translation.synchronizer')->synchronizeFields($entity, $entity->language()->id, $attributes->get('source_langcode'));
+  }
+}
+
+/**
+ * Act on a specific type of entity before it is created or updated.
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $entity
+ *   The entity object.
+ *
+ * @ingroup entity_crud
+ * @see hook_entity_presave()
+ */
+function hook_ENTITY_TYPE_presave(Drupal\Core\Entity\EntityInterface $entity) {
+  if ($entity->isTranslatable()) {
+    $attributes = \Drupal::request()->attributes;
+    \Drupal::service('content_translation.synchronizer')->synchronizeFields($entity, $entity->language()->id, $attributes->get('source_langcode'));
+  }
 }
 
 /**
@@ -298,6 +606,9 @@ function hook_entity_presave(Drupal\Core\Entity\EntityInterface $entity) {
  *
  * @param \Drupal\Core\Entity\EntityInterface $entity
  *   The entity object.
+ *
+ * @ingroup entity_crud
+ * @see hook_ENTITY_TYPE_insert()
  */
 function hook_entity_insert(Drupal\Core\Entity\EntityInterface $entity) {
   // Insert the new entity into a fictional table of all entities.
@@ -311,6 +622,29 @@ function hook_entity_insert(Drupal\Core\Entity\EntityInterface $entity) {
     ->execute();
 }
 
+/**
+ * Respond to creation of a new entity of a particular type.
+ *
+ * This hook runs once the entity has been stored. Note that hook
+ * implementations may not alter the stored entity data.
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $entity
+ *   The entity object.
+ *
+ * @ingroup entity_crud
+ * @see hook_entity_insert()
+ */
+function hook_ENTITY_TYPE_insert(Drupal\Core\Entity\EntityInterface $entity) {
+  // Insert the new entity into a fictional table of this type of entity.
+  db_insert('example_entity')
+    ->fields(array(
+      'id' => $entity->id(),
+      'created' => REQUEST_TIME,
+      'updated' => REQUEST_TIME,
+    ))
+    ->execute();
+}
+
 /**
  * Respond to updates to an entity.
  *
@@ -319,6 +653,9 @@ function hook_entity_insert(Drupal\Core\Entity\EntityInterface $entity) {
  *
  * @param \Drupal\Core\Entity\EntityInterface $entity
  *   The entity object.
+ *
+ * @ingroup entity_crud
+ * @see hook_ENTITY_TYPE_update()
  */
 function hook_entity_update(Drupal\Core\Entity\EntityInterface $entity) {
   // Update the entity's entry in a fictional table of all entities.
@@ -331,6 +668,28 @@ function hook_entity_update(Drupal\Core\Entity\EntityInterface $entity) {
     ->execute();
 }
 
+/**
+ * Respond to updates to an entity of a particular type.
+ *
+ * This hook runs once the entity storage has been updated. Note that hook
+ * implementations may not alter the stored entity data.
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $entity
+ *   The entity object.
+ *
+ * @ingroup entity_crud
+ * @see hook_entity_update()
+ */
+function hook_ENTITY_TYPE_update(Drupal\Core\Entity\EntityInterface $entity) {
+  // Update the entity's entry in a fictional table of this type of entity.
+  db_update('example_entity')
+    ->fields(array(
+      'updated' => REQUEST_TIME,
+    ))
+    ->condition('id', $entity->id())
+    ->execute();
+}
+
 /**
  * Respond to creation of a new entity translation.
  *
@@ -339,6 +698,9 @@ function hook_entity_update(Drupal\Core\Entity\EntityInterface $entity) {
  *
  * @param \Drupal\Core\Entity\EntityInterface $translation
  *   The entity object of the translation just stored.
+ *
+ * @ingroup entity_crud
+ * @see hook_ENTITY_TYPE_translation_insert()
  */
 function hook_entity_translation_insert(\Drupal\Core\Entity\EntityInterface $translation) {
   $variables = array(
@@ -348,6 +710,26 @@ function hook_entity_translation_insert(\Drupal\Core\Entity\EntityInterface $tra
   \Drupal::logger('example')->notice('The @language translation of @label has just been stored.', $variables);
 }
 
+/**
+ * Respond to creation of a new entity translation of a particular type.
+ *
+ * This hook runs once the entity translation has been stored. Note that hook
+ * implementations may not alter the stored entity translation data.
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $translation
+ *   The entity object of the translation just stored.
+ *
+ * @ingroup entity_crud
+ * @see hook_entity_translation_insert()
+ */
+function hook_ENTITY_TYPE_translation_insert(\Drupal\Core\Entity\EntityInterface $translation) {
+  $variables = array(
+    '@language' => $translation->language()->name,
+    '@label' => $translation->getUntranslated()->label(),
+  );
+  \Drupal::logger('example')->notice('The @language translation of @label has just been stored.', $variables);
+}
+
 /**
  * Respond to entity translation deletion.
  *
@@ -355,6 +737,9 @@ function hook_entity_translation_insert(\Drupal\Core\Entity\EntityInterface $tra
  *
  * @param \Drupal\Core\Entity\EntityInterface $entity
  *   The original entity object.
+ *
+ * @ingroup entity_crud
+ * @see hook_ENTITY_TYPE_translation_delete()
  */
 function hook_entity_translation_delete(\Drupal\Core\Entity\EntityInterface $translation) {
   $languages = \Drupal::languageManager()->getLanguages();
@@ -365,11 +750,34 @@ function hook_entity_translation_delete(\Drupal\Core\Entity\EntityInterface $tra
   \Drupal::logger('example')->notice('The @language translation of @label has just been deleted.', $variables);
 }
 
+/**
+ * Respond to entity translation deletion of a particular type.
+ *
+ * This hook runs once the entity translation has been deleted from storage.
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $entity
+ *   The original entity object.
+ *
+ * @ingroup entity_crud
+ * @see hook_entity_translation_delete()
+ */
+function hook_ENTITY_TYPE_translation_delete(\Drupal\Core\Entity\EntityInterface $translation) {
+  $languages = \Drupal::languageManager()->getLanguages();
+  $variables = array(
+    '@language' => $languages[$langcode]->name,
+    '@label' => $entity->label(),
+  );
+  \Drupal::logger('example')->notice('The @language translation of @label has just been deleted.', $variables);
+}
+
 /**
  * Act before entity deletion.
  *
  * @param \Drupal\Core\Entity\EntityInterface $entity
  *   The entity object for the entity that is about to be deleted.
+ *
+ * @ingroup entity_crud
+ * @see hook_ENTITY_TYPE_predelete()
  */
 function hook_entity_predelete(Drupal\Core\Entity\EntityInterface $entity) {
   // Count references to this entity in a custom table before they are removed
@@ -390,6 +798,34 @@ function hook_entity_predelete(Drupal\Core\Entity\EntityInterface $entity) {
     ->execute();
 }
 
+/**
+ * Act before entity deletion of a particular entity type.
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $entity
+ *   The entity object for the entity that is about to be deleted.
+ *
+ * @ingroup entity_crud
+ * @see hook_entity_predelete()
+ */
+function hook_ENTITY_TYPE_predelete(Drupal\Core\Entity\EntityInterface $entity) {
+  // Count references to this entity in a custom table before they are removed
+  // upon entity deletion.
+  $id = $entity->id();
+  $type = $entity->getEntityTypeId();
+  $count = db_select('example_entity_data')
+    ->condition('type', $type)
+    ->condition('id', $id)
+    ->countQuery()
+    ->execute()
+    ->fetchField();
+
+  // Log the count in a table that records this statistic for deleted entities.
+  db_merge('example_deleted_entity_statistics')
+    ->key(array('type' => $type, 'id' => $id))
+    ->fields(array('count' => $count))
+    ->execute();
+}
+
 /**
  * Respond to entity deletion.
  *
@@ -397,6 +833,9 @@ function hook_entity_predelete(Drupal\Core\Entity\EntityInterface $entity) {
  *
  * @param \Drupal\Core\Entity\EntityInterface $entity
  *   The entity object for the entity that has been deleted.
+ *
+ * @ingroup entity_crud
+ * @see hook_ENTITY_TYPE_delete()
  */
 function hook_entity_delete(Drupal\Core\Entity\EntityInterface $entity) {
   // Delete the entity's entry from a fictional table of all entities.
@@ -406,6 +845,25 @@ function hook_entity_delete(Drupal\Core\Entity\EntityInterface $entity) {
     ->execute();
 }
 
+/**
+ * Respond to entity deletion of a particular type.
+ *
+ * This hook runs once the entity has been deleted from the storage.
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $entity
+ *   The entity object for the entity that has been deleted.
+ *
+ * @ingroup entity_crud
+ * @see hook_entity_delete()
+ */
+function hook_ENTITY_TYPE_delete(Drupal\Core\Entity\EntityInterface $entity) {
+  // Delete the entity's entry from a fictional table of all entities.
+  db_delete('example_entity')
+    ->condition('type', $entity->getEntityTypeId())
+    ->condition('id', $entity->id())
+    ->execute();
+}
+
 /**
  * Respond to entity revision deletion.
  *
@@ -413,9 +871,33 @@ function hook_entity_delete(Drupal\Core\Entity\EntityInterface $entity) {
  *
  * @param \Drupal\Core\Entity\EntityInterface $entity
  *   The entity object for the entity revision that has been deleted.
+ *
+ * @ingroup entity_crud
+ * @see hook_ENTITY_TYPE_revision_delete()
  */
 function hook_entity_revision_delete(Drupal\Core\Entity\EntityInterface $entity) {
-  // @todo: code example
+  $referenced_files_by_field = _editor_get_file_uuids_by_field($entity);
+  foreach ($referenced_files_by_field as $field => $uuids) {
+    _editor_delete_file_usage($uuids, $entity, 1);
+  }
+}
+
+/**
+ * Respond to entity revision deletion of a particular type.
+ *
+ * This hook runs once the entity revision has been deleted from the storage.
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $entity
+ *   The entity object for the entity revision that has been deleted.
+ *
+ * @ingroup entity_crud
+ * @see hook_entity_revision_delete()
+ */
+function hook_ENTITY_TYPE_revision_delete(Drupal\Core\Entity\EntityInterface $entity) {
+  $referenced_files_by_field = _editor_get_file_uuids_by_field($entity);
+  foreach ($referenced_files_by_field as $field => $uuids) {
+    _editor_delete_file_usage($uuids, $entity, 1);
+  }
 }
 
 /**
@@ -453,9 +935,9 @@ function hook_entity_query_alter(\Drupal\Core\Entity\Query\QueryInterface $query
  * drupal_render().
  *
  * @see hook_entity_view_alter()
- * @see hook_comment_view()
- * @see hook_node_view()
- * @see hook_user_view()
+ * @see hook_ENTITY_TYPE_view()
+ *
+ * @ingroup entity_crud
  */
 function hook_entity_view(array &$build, \Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, $view_mode, $langcode) {
   // Only do the extra work if the component is configured to be displayed.
@@ -470,7 +952,43 @@ function hook_entity_view(array &$build, \Drupal\Core\Entity\EntityInterface $en
 }
 
 /**
- * Alter the results of ENTITY_view().
+ * Act on entities of a particular type being assembled before rendering.
+ *
+ * @param &$build
+ *   A renderable array representing the entity content.
+ * @param \Drupal\Core\Entity\EntityInterface $entity
+ *   The entity object.
+ * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
+ *   The entity view display holding the display options configured for the
+ *   entity components.
+ * @param $view_mode
+ *   The view mode the entity is rendered in.
+ * @param $langcode
+ *   The language code used for rendering.
+ *
+ * The module may add elements to $build prior to rendering. The
+ * structure of $build is a renderable array as expected by
+ * drupal_render().
+ *
+ * @see hook_ENTITY_TYPE_view_alter()
+ * @see hook_entity_view()
+ *
+ * @ingroup entity_crud
+ */
+function hook_ENTITY_TYPE_view(array &$build, \Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, $view_mode, $langcode) {
+  // Only do the extra work if the component is configured to be displayed.
+  // This assumes a 'mymodule_addition' extra field has been defined for the
+  // entity bundle in hook_entity_extra_field_info().
+  if ($display->getComponent('mymodule_addition')) {
+    $build['mymodule_addition'] = array(
+      '#markup' => mymodule_addition($entity),
+      '#theme' => 'mymodule_my_additional_field',
+    );
+  }
+}
+
+/**
+ * Alter the results of the entity build array.
  *
  * This hook is called after the content has been assembled in a structured
  * array and may be used for doing processing which requires that the complete
@@ -491,10 +1009,9 @@ function hook_entity_view(array &$build, \Drupal\Core\Entity\EntityInterface $en
  *   entity components.
  *
  * @see hook_entity_view()
- * @see hook_comment_view_alter()
- * @see hook_node_view_alter()
- * @see hook_taxonomy_term_view_alter()
- * @see hook_user_view_alter()
+ * @see hook_ENTITY_TYPE_view_alter()
+ *
+ * @ingroup entity_crud
  */
 function hook_entity_view_alter(array &$build, Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display) {
   if ($build['#view_mode'] == 'full' && isset($build['an_additional_field'])) {
@@ -506,6 +1023,42 @@ function hook_entity_view_alter(array &$build, Drupal\Core\Entity\EntityInterfac
   }
 }
 
+/**
+ * Alter the results of the entity build array for a particular entity type.
+ *
+ * This hook is called after the content has been assembled in a structured
+ * array and may be used for doing processing which requires that the complete
+ * entity content structure has been built.
+ *
+ * If a module wishes to act on the rendered HTML of the entity rather than the
+ * structured content array, it may use this hook to add a #post_render
+ * callback. Alternatively, it could also implement hook_preprocess_HOOK() for
+ * the particular entity type template, if there is one (e.g., node.html.twig).
+ * See drupal_render() and _theme() for details.
+ *
+ * @param array &$build
+ *   A renderable array representing the entity content.
+ * @param \Drupal\Core\Entity\EntityInterface $entity
+ *   The entity object being rendered.
+ * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
+ *   The entity view display holding the display options configured for the
+ *   entity components.
+ *
+ * @see hook_ENTITY_TYPE_view()
+ * @see hook_entity_view_alter()
+ *
+ * @ingroup entity_crud
+ */
+function hook_ENTITY_TYPE_view_alter(array &$build, Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display) {
+  if ($build['#view_mode'] == 'full' && isset($build['an_additional_field'])) {
+    // Change its weight.
+    $build['an_additional_field']['#weight'] = -10;
+
+    // Add a #post_render callback to act on the rendered HTML of the entity.
+    $build['#post_render'][] = 'my_module_node_post_render';
+  }
+}
+
 /**
  * Act on entities as they are being prepared for view.
  *
@@ -522,6 +1075,8 @@ function hook_entity_view_alter(array &$build, Drupal\Core\Entity\EntityInterfac
  *   for the entity components, keyed by bundle name.
  * @param string $view_mode
  *   The view mode.
+ *
+ * @ingroup entity_crud
  */
 function hook_entity_prepare_view($entity_type_id, array $entities, array $displays, $view_mode) {
   // Load a specific node into the user object for later theming.
@@ -554,6 +1109,8 @@ function hook_entity_prepare_view($entity_type_id, array $entities, array $displ
  * @param array $context
  *   Array with additional context information, currently only contains the
  *   langcode the entity is viewed in.
+ *
+ * @ingroup entity_crud
  */
 function hook_entity_view_mode_alter(&$view_mode, Drupal\Core\Entity\EntityInterface $entity, $context) {
   // For nodes, change the view mode when it is teaser.
@@ -563,7 +1120,7 @@ function hook_entity_view_mode_alter(&$view_mode, Drupal\Core\Entity\EntityInter
 }
 
 /**
- * Alters entity renderable values before cache checking in drupal_render().
+ * Alter entity renderable values before cache checking in drupal_render().
  *
  * Invoked for a specific entity type.
  *
@@ -582,13 +1139,16 @@ function hook_entity_view_mode_alter(&$view_mode, Drupal\Core\Entity\EntityInter
  *
  * @see drupal_render()
  * @see \Drupal\Core\Entity\EntityViewBuilder
+ * @see hook_entity_build_defaults_alter()
+ *
+ * @ingroup entity_crud
  */
 function hook_ENTITY_TYPE_build_defaults_alter(array &$build, \Drupal\Core\Entity\EntityInterface $entity, $view_mode, $langcode) {
 
 }
 
 /**
- * Alters entity renderable values before cache checking in drupal_render().
+ * Alter entity renderable values before cache checking in drupal_render().
  *
  * The values in the #cache key of the renderable array are used to determine if
  * a cache entry exists for the entity's rendered output. Ideally only values
@@ -605,13 +1165,16 @@ function hook_ENTITY_TYPE_build_defaults_alter(array &$build, \Drupal\Core\Entit
  *
  * @see drupal_render()
  * @see \Drupal\Core\Entity\EntityViewBuilder
+ * @see hook_ENTITY_TYPE_build_defaults_alter()
+ *
+ * @ingroup entity_crud
  */
 function hook_entity_build_defaults_alter(array &$build, \Drupal\Core\Entity\EntityInterface $entity, $view_mode, $langcode) {
 
 }
 
 /**
- * Alters the settings used for displaying an entity.
+ * Alter the settings used for displaying an entity.
  *
  * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
  *   The entity view display that will be used to display the entity
@@ -621,6 +1184,8 @@ function hook_entity_build_defaults_alter(array &$build, \Drupal\Core\Entity\Ent
  *   - entity_type: The entity type, e.g., 'node' or 'user'.
  *   - bundle: The bundle, e.g., 'page' or 'article'.
  *   - view_mode: The view mode, e.g. 'full', 'teaser'...
+ *
+ * @ingroup entity_crud
  */
 function hook_entity_view_display_alter(\Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, array $context) {
   // Leave field labels out of the search index.
@@ -644,6 +1209,8 @@ function hook_entity_view_display_alter(\Drupal\Core\Entity\Display\EntityViewDi
  *   - entity: The entity being rendered.
  *   - view_mode: The view mode; for example, 'full' or 'teaser'.
  *   - display: The EntityDisplay holding the display options.
+ *
+ * @ingroup entity_crud
  */
 function hook_entity_display_build_alter(&$build, $context) {
   // Append RDF term mappings on displayed taxonomy links.
@@ -678,6 +1245,9 @@ function hook_entity_display_build_alter(&$build, $context) {
  *   An associative array containing the current state of the form.
  *
  * @see \Drupal\Core\Entity\EntityForm::prepareEntity()
+ * @see hook_ENTITY_TYPE_prepare_form()
+ *
+ * @ingroup entity_crud
  */
 function hook_entity_prepare_form(\Drupal\Core\Entity\EntityInterface $entity, $operation, array &$form_state) {
   if ($operation == 'edit') {
@@ -687,7 +1257,33 @@ function hook_entity_prepare_form(\Drupal\Core\Entity\EntityInterface $entity, $
 }
 
 /**
- * Alters the settings used for displaying an entity form.
+ * Acts on a particular type of entity object about to be in an entity form.
+ *
+ * This can be typically used to pre-fill entity values or change the form state
+ * before the entity form is built. It is invoked just once when first building
+ * the entity form. Rebuilds will not trigger a new invocation.
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $entity
+ *   The entity that is about to be shown on the form.
+ * @param $operation
+ *   The current operation.
+ * @param array $form_state
+ *   An associative array containing the current state of the form.
+ *
+ * @see \Drupal\Core\Entity\EntityForm::prepareEntity()
+ * @see hook_entity_prepare_form()
+ *
+ * @ingroup entity_crud
+ */
+function hook_ENTITY_TYPE_prepare_form(\Drupal\Core\Entity\EntityInterface $entity, $operation, array &$form_state) {
+  if ($operation == 'edit') {
+    $entity->label->value = 'Altered label';
+    $form_state['mymodule']['label_altered'] = TRUE;
+  }
+}
+
+/**
+ * Alter the settings used for displaying an entity form.
  *
  * @param \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display
  *   The entity_form_display object that will be used to display the entity form
@@ -697,6 +1293,8 @@ function hook_entity_prepare_form(\Drupal\Core\Entity\EntityInterface $entity, $
  *   - entity_type: The entity type, e.g., 'node' or 'user'.
  *   - bundle: The bundle, e.g., 'page' or 'article'.
  *   - form_mode: The form mode, e.g. 'default', 'profile', 'register'...
+ *
+ * @ingroup entity_crud
  */
 function hook_entity_form_display_alter(\Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display, array $context) {
   // Hide the 'user_picture' field from the register form.
@@ -736,7 +1334,7 @@ function hook_entity_base_field_info(\Drupal\Core\Entity\EntityTypeInterface $en
 }
 
 /**
- * Alters base field definitions for a content entity type.
+ * Alter base field definitions for a content entity type.
  *
  * @param \Drupal\Core\Field\FieldDefinitionInterface[] $fields
  *   The array of base field definitions for the entity type.
@@ -792,7 +1390,7 @@ function hook_entity_bundle_field_info(\Drupal\Core\Entity\EntityTypeInterface $
 }
 
 /**
- * Alters bundle field definitions.
+ * Alter bundle field definitions.
  *
  * @param \Drupal\Core\Field\FieldDefinitionInterface[] $fields
  *   The array of bundle field definitions.
@@ -845,7 +1443,7 @@ function hook_entity_field_storage_info(\Drupal\Core\Entity\EntityTypeInterface
 }
 
 /**
- * Alters field storage definitions for a content entity type.
+ * Alter field storage definitions for a content entity type.
  *
  * @param \Drupal\Core\Field\FieldStorageDefinitionInterface[] $fields
  *   The array of field storage definitions for the entity type.
@@ -928,7 +1526,7 @@ function hook_entity_field_access($operation, \Drupal\Core\Field\FieldDefinition
 }
 
 /**
- * Alters the default access behavior for a given field.
+ * Alter the default access behavior for a given field.
  *
  * Use this hook to override access grants from another module. Note that the
  * original default access flag is masked under the ':default' key.
diff --git a/core/modules/system/src/Tests/Entity/EntityCrudHookTest.php b/core/modules/system/src/Tests/Entity/EntityCrudHookTest.php
index 7067f9b6db9f..2f41f43cae6f 100644
--- a/core/modules/system/src/Tests/Entity/EntityCrudHookTest.php
+++ b/core/modules/system/src/Tests/Entity/EntityCrudHookTest.php
@@ -17,13 +17,13 @@
  * deleting an entity.
  *
  * Tested hooks are:
- * - hook_entity_insert()
- * - hook_entity_load()
- * - hook_entity_update()
- * - hook_entity_predelete()
- * - hook_entity_delete()
- * As well as all type-specific hooks, like hook_node_insert(),
- * hook_comment_update(), etc.
+ * - hook_entity_insert() and hook_ENTITY_TYPE_insert()
+ * - hook_entity_load() and hook_ENTITY_TYPE_load()
+ * - hook_entity_update() and hook_ENTITY_TYPE_update()
+ * - hook_entity_predelete() and hook_ENTITY_TYPE_predelete()
+ * - hook_entity_delete() and hook_ENTITY_TYPE_delete()
+ *
+ * These hooks are each tested for several entity types.
  *
  * @group Entity
  */
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 3d67b659e5bf..4a57520bdbcc 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -1007,7 +1007,7 @@ function system_form_user_register_form_alter(&$form, &$form_state) {
 }
 
 /**
- * Implements hook_user_presave().
+ * Implements hook_ENTITY_TYPE_presave() for user entities.
  */
 function system_user_presave(UserInterface $account) {
   $config = \Drupal::config('system.date');
diff --git a/core/modules/system/tests/modules/entity_crud_hook_test/entity_crud_hook_test.module b/core/modules/system/tests/modules/entity_crud_hook_test/entity_crud_hook_test.module
index e88ae9978616..c7f20c366d84 100644
--- a/core/modules/system/tests/modules/entity_crud_hook_test/entity_crud_hook_test.module
+++ b/core/modules/system/tests/modules/entity_crud_hook_test/entity_crud_hook_test.module
@@ -15,49 +15,49 @@ function entity_crud_hook_test_entity_create(EntityInterface $entity) {
 }
 
 /**
- * Implements hook_block_create().
+ * Implements hook_ENTITY_TYPE_create() for block entities.
  */
 function entity_crud_hook_test_block_create() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_comment_create().
+ * Implements hook_ENTITY_TYPE_create() for comment entities.
  */
 function entity_crud_hook_test_comment_create() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_file_create().
+ * Implements hook_ENTITY_TYPE_create() for file entities.
  */
 function entity_crud_hook_test_file_create() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_node_create().
+ * Implements hook_ENTITY_TYPE_create() for node entities.
  */
 function entity_crud_hook_test_node_create() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_taxonomy_term_create().
+ * Implements hook_ENTITY_TYPE_create() for taxonomy_term entities.
  */
 function entity_crud_hook_test_taxonomy_term_create() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_taxonomy_vocabulary_create().
+ * Implements hook_ENTITY_TYPE_create() for taxonomy_vocabulary entities.
  */
 function entity_crud_hook_test_taxonomy_vocabulary_create() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_user_create().
+ * Implements hook_ENTITY_TYPE_create() for user entities.
  */
 function entity_crud_hook_test_user_create() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
@@ -71,49 +71,49 @@ function entity_crud_hook_test_entity_presave(EntityInterface $entity) {
 }
 
 /**
- * Implements hook_block_presave().
+ * Implements hook_ENTITY_TYPE_presave() for block entities.
  */
 function entity_crud_hook_test_block_presave() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_comment_presave().
+ * Implements hook_ENTITY_TYPE_presave() for comment entities.
  */
 function entity_crud_hook_test_comment_presave() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_file_presave().
+ * Implements hook_ENTITY_TYPE_presave() for file entities.
  */
 function entity_crud_hook_test_file_presave() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_node_presave().
+ * Implements hook_ENTITY_TYPE_presave() for node entities.
  */
 function entity_crud_hook_test_node_presave() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_taxonomy_term_presave().
+ * Implements hook_ENTITY_TYPE_presave() for taxonomy_term entities.
  */
 function entity_crud_hook_test_taxonomy_term_presave() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_taxonomy_vocabulary_presave().
+ * Implements hook_ENTITY_TYPE_presave() for taxonomy_vocabulary entities.
  */
 function entity_crud_hook_test_taxonomy_vocabulary_presave() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_user_presave().
+ * Implements hook_ENTITY_TYPE_presave() for user entities.
  */
 function entity_crud_hook_test_user_presave() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
@@ -127,49 +127,49 @@ function entity_crud_hook_test_entity_insert(EntityInterface $entity) {
 }
 
 /**
- * Implements hook_block_insert().
+ * Implements hook_ENTITY_TYPE_insert() for block entities.
  */
 function entity_crud_hook_test_block_insert() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_comment_insert().
+ * Implements hook_ENTITY_TYPE_insert() for comment entities.
  */
 function entity_crud_hook_test_comment_insert() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_file_insert().
+ * Implements hook_ENTITY_TYPE_insert() for file entities.
  */
 function entity_crud_hook_test_file_insert() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_node_insert().
+ * Implements hook_ENTITY_TYPE_insert() for node entities.
  */
 function entity_crud_hook_test_node_insert() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_taxonomy_term_insert().
+ * Implements hook_ENTITY_TYPE_insert() for taxonomy_term entities.
  */
 function entity_crud_hook_test_taxonomy_term_insert() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_taxonomy_vocabulary_insert().
+ * Implements hook_ENTITY_TYPE_insert() for taxonomy_vocabulary entities.
  */
 function entity_crud_hook_test_taxonomy_vocabulary_insert() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_user_insert().
+ * Implements hook_ENTITY_TYPE_insert() for user entities.
  */
 function entity_crud_hook_test_user_insert() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
@@ -183,49 +183,49 @@ function entity_crud_hook_test_entity_load(array $entities, $type) {
 }
 
 /**
- * Implements hook_block_load().
+ * Implements hook_ENTITY_TYPE_load() for block entities.
  */
 function entity_crud_hook_test_block_load() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_comment_load().
+ * Implements hook_ENTITY_TYPE_load() for comment entities.
  */
 function entity_crud_hook_test_comment_load() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_file_load().
+ * Implements hook_ENTITY_TYPE_load() for file entities.
  */
 function entity_crud_hook_test_file_load() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_node_load().
+ * Implements hook_ENTITY_TYPE_load() for node entities.
  */
 function entity_crud_hook_test_node_load() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_taxonomy_term_load().
+ * Implements hook_ENTITY_TYPE_load() for taxonomy_term entities.
  */
 function entity_crud_hook_test_taxonomy_term_load() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_taxonomy_vocabulary_load().
+ * Implements hook_ENTITY_TYPE_load() for taxonomy_vocabulary entities.
  */
 function entity_crud_hook_test_taxonomy_vocabulary_load() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_user_load().
+ * Implements hook_ENTITY_TYPE_load() for user entities.
  */
 function entity_crud_hook_test_user_load() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
@@ -239,49 +239,49 @@ function entity_crud_hook_test_entity_update(EntityInterface $entity) {
 }
 
 /**
- * Implements hook_block_update().
+ * Implements hook_ENTITY_TYPE_update() for block entities.
  */
 function entity_crud_hook_test_block_update() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_comment_update().
+ * Implements hook_ENTITY_TYPE_update() for comment entities.
  */
 function entity_crud_hook_test_comment_update() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_file_update().
+ * Implements hook_ENTITY_TYPE_update() for file entities.
  */
 function entity_crud_hook_test_file_update() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_node_update().
+ * Implements hook_ENTITY_TYPE_update() for node entities.
  */
 function entity_crud_hook_test_node_update() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_taxonomy_term_update().
+ * Implements hook_ENTITY_TYPE_update() for taxonomy_term entities.
  */
 function entity_crud_hook_test_taxonomy_term_update() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_taxonomy_vocabulary_update().
+ * Implements hook_ENTITY_TYPE_update() for taxonomy_vocabulary entities.
  */
 function entity_crud_hook_test_taxonomy_vocabulary_update() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_user_update().
+ * Implements hook_ENTITY_TYPE_update() for user entities.
  */
 function entity_crud_hook_test_user_update() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
@@ -295,49 +295,49 @@ function entity_crud_hook_test_entity_predelete(EntityInterface $entity) {
 }
 
 /**
- * Implements hook_block_predelete().
+ * Implements hook_ENTITY_TYPE_predelete() for block entities.
  */
 function entity_crud_hook_test_block_predelete() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_comment_predelete().
+ * Implements hook_ENTITY_TYPE_predelete() for comment entities.
  */
 function entity_crud_hook_test_comment_predelete() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_file_predelete().
+ * Implements hook_ENTITY_TYPE_predelete() for file entities.
  */
 function entity_crud_hook_test_file_predelete() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_node_predelete().
+ * Implements hook_ENTITY_TYPE_predelete() for node entities.
  */
 function entity_crud_hook_test_node_predelete() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_taxonomy_term_predelete().
+ * Implements hook_ENTITY_TYPE_predelete() for taxonomy_term entities.
  */
 function entity_crud_hook_test_taxonomy_term_predelete() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_taxonomy_vocabulary_predelete().
+ * Implements hook_ENTITY_TYPE_predelete() for taxonomy_vocabulary entities.
  */
 function entity_crud_hook_test_taxonomy_vocabulary_predelete() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_user_predelete().
+ * Implements hook_ENTITY_TYPE_predelete() for user entities.
  */
 function entity_crud_hook_test_user_predelete() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
@@ -351,49 +351,49 @@ function entity_crud_hook_test_entity_delete(EntityInterface $entity) {
 }
 
 /**
- * Implements hook_block_delete().
+ * Implements hook_ENTITY_TYPE_delete() for block entities.
  */
 function entity_crud_hook_test_block_delete() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_comment_delete().
+ * Implements hook_ENTITY_TYPE_delete() for comment entities.
  */
 function entity_crud_hook_test_comment_delete() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_file_delete().
+ * Implements hook_ENTITY_TYPE_delete() for file entities.
  */
 function entity_crud_hook_test_file_delete() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_node_delete().
+ * Implements hook_ENTITY_TYPE_delete() for node entities.
  */
 function entity_crud_hook_test_node_delete() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_taxonomy_term_delete().
+ * Implements hook_ENTITY_TYPE_delete() for taxonomy_term entities.
  */
 function entity_crud_hook_test_taxonomy_term_delete() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_taxonomy_vocabulary_delete().
+ * Implements hook_ENTITY_TYPE_delete() for taxonomy_vocabulary entities.
  */
 function entity_crud_hook_test_taxonomy_vocabulary_delete() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
 }
 
 /**
- * Implements hook_user_delete().
+ * Implements hook_ENTITY_TYPE_delete() for user entities.
  */
 function entity_crud_hook_test_user_delete() {
   $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
diff --git a/core/modules/system/tests/modules/menu_test/menu_test.module b/core/modules/system/tests/modules/menu_test/menu_test.module
index 9f1d06d26885..c222ce805b1a 100644
--- a/core/modules/system/tests/modules/menu_test/menu_test.module
+++ b/core/modules/system/tests/modules/menu_test/menu_test.module
@@ -167,21 +167,21 @@ function menu_test_menu_name($new_name = '') {
 }
 
 /**
- * Implements hook_menu_link_insert().
+ * Implements hook_ENTITY_TYPE_insert() for menu_link entities.
  */
 function menu_test_menu_link_insert(MenuLink $item) {
   menu_test_static_variable('insert');
 }
 
 /**
- * Implements hook_menu_link_update().
+ * Implements hook_ENTITY_TYPE_update() for menu_link entities.
  */
 function menu_test_menu_link_update(MenuLink $item) {
   menu_test_static_variable('update');
 }
 
 /**
- * Implements hook_menu_link_delete().
+ * Implements hook_ENTITY_TYPE_delete() for menu_link entities.
  */
 function menu_test_menu_link_delete(MenuLink $item) {
   menu_test_static_variable('delete');
diff --git a/core/modules/taxonomy/taxonomy.api.php b/core/modules/taxonomy/taxonomy.api.php
deleted file mode 100644
index 9fa84c1db2bd..000000000000
--- a/core/modules/taxonomy/taxonomy.api.php
+++ /dev/null
@@ -1,310 +0,0 @@
-<?php
-
-use Drupal\Core\Entity\EntityInterface;
-
-/**
- * @file
- * Hooks provided by the Taxonomy module.
- */
-
-/**
- * @addtogroup hooks
- * @{
- */
-
-/**
- * Act on a newly created vocabulary.
- *
- * This hook runs after a new vocabulary object has just been instantiated. It
- * can be used to set initial values, e.g. to provide defaults.
- *
- * @param \Drupal\taxonomy\Entity\Vocabulary $vocabulary
- *   The vocabulary object.
- */
-function hook_taxonomy_vocabulary_create(\Drupal\taxonomy\Entity\Vocabulary $vocabulary) {
-  if (!isset($vocabulary->foo)) {
-    $vocabulary->foo = NULL;
-  }
-}
-
-/**
- * Act on taxonomy vocabularies when loaded.
- *
- * Modules implementing this hook can act on the vocabulary objects before they
- * are returned by entity_load_multiple().
- *
- * @param array $vocabularies
- *   An array of taxonomy vocabulary entities.
- */
-function hook_taxonomy_vocabulary_load(array $vocabularies) {
-  $result = db_select('mytable', 'm')
-    ->fields('m', array('vid', 'foo'))
-    ->condition('m.vid', array_keys($vocabularies), 'IN')
-    ->execute();
-  foreach ($result as $record) {
-    $vocabularies[$record->vid]->foo = $record->foo;
-  }
-}
-
-/**
- * Act on taxonomy vocabularies before they are saved.
- *
- * Modules implementing this hook can act on the vocabulary object before it is
- * inserted or updated.
- *
- * @param \Drupal\taxonomy\Entity\Vocabulary $vocabulary
- *   A taxonomy vocabulary entity.
- */
-function hook_taxonomy_vocabulary_presave(Drupal\taxonomy\Entity\Vocabulary $vocabulary) {
-  $vocabulary->foo = 'bar';
-}
-
-/**
- * Act on taxonomy vocabularies when inserted.
- *
- * Modules implementing this hook can act on the vocabulary object when saved
- * to the database.
- *
- * @param \Drupal\taxonomy\Entity\Vocabulary $vocabulary
- *   A taxonomy vocabulary entity.
- */
-function hook_taxonomy_vocabulary_insert(Drupal\taxonomy\Entity\Vocabulary $vocabulary) {
-  if ($vocabulary->id() == 'my_vocabulary') {
-    $vocabulary->weight = 100;
-  }
-}
-
-/**
- * Act on taxonomy vocabularies when updated.
- *
- * Modules implementing this hook can act on the vocabulary object when updated.
- *
- * @param \Drupal\taxonomy\Entity\Vocabulary $vocabulary
- *   A taxonomy vocabulary entity.
- */
-function hook_taxonomy_vocabulary_update(Drupal\taxonomy\Entity\Vocabulary $vocabulary) {
-  db_update('mytable')
-    ->fields(array('foo' => $vocabulary->foo))
-    ->condition('vid', $vocabulary->id())
-    ->execute();
-}
-
-/**
- * Act before taxonomy vocabulary deletion.
- *
- * This hook is invoked before entity_bundle_delete() is called and before
- * the vocabulary is actually removed.
- *
- * @param \Drupal\taxonomy\Entity\Vocabulary $vocabulary
- *   The taxonomy vocabulary entity that is about to be deleted.
- *
- * @see hook_taxonomy_vocabulary_delete()
- */
-function hook_taxonomy_vocabulary_predelete(Drupal\taxonomy\Entity\Vocabulary $vocabulary) {
-  db_delete('mytable_index')
-    ->condition('vid', $vocabulary->id())
-    ->execute();
-}
-
-/**
- * Respond to taxonomy vocabulary deletion.
- *
- * This hook is invoked after entity_bundle_delete() has been called and after
- * the vocabulary has been removed.
- *
- * @param \Drupal\taxonomy\Entity\Vocabulary $vocabulary
- *   The taxonomy vocabulary entity that has been deleted.
- *
- * @see hook_taxonomy_vocabulary_predelete()
- */
-function hook_taxonomy_vocabulary_delete(Drupal\taxonomy\Entity\Vocabulary $vocabulary) {
-  db_delete('mytable')
-    ->condition('vid', $vocabulary->id())
-    ->execute();
-}
-
-/**
- * Act on a newly created term.
- *
- * This hook runs after a new term object has just been instantiated. It can be
- * used to set initial values, e.g. to provide defaults.
- *
- * @param \Drupal\taxonomy\Entity\Term $term
- *   The term object.
- */
-function hook_taxonomy_term_create(\Drupal\taxonomy\Entity\Term $term) {
-  if (!isset($term->foo)) {
-    $term->foo = 'some_initial_value';
-  }
-}
-
-/**
- * Act on taxonomy terms when loaded.
- *
- * Modules implementing this hook can act on the term objects returned by
- * entity_load_multiple().
- *
- * For performance reasons, information to be added to term objects should be
- * loaded in a single query for all terms where possible.
- *
- * Since terms are stored and retrieved from cache during a page request, avoid
- * altering properties provided by the {taxonomy_term_data} table, since this
- * may affect the way results are loaded from cache in subsequent calls.
- *
- * @param array $terms
- *   An array of taxonomy term entities, indexed by tid.
- */
-function hook_taxonomy_term_load(array $terms) {
-  $result = db_select('mytable', 'm')
-    ->fields('m', array('tid', 'foo'))
-    ->condition('m.tid', array_keys($terms), 'IN')
-    ->execute();
-  foreach ($result as $record) {
-    $terms[$record->tid]->foo = $record->foo;
-  }
-}
-
-/**
- * Act on taxonomy terms before they are saved.
- *
- * Modules implementing this hook can act on the term object before it is
- * inserted or updated.
- *
- * @param \Drupal\taxonomy\Term $term
- *   A taxonomy term entity.
- */
-function hook_taxonomy_term_presave(Drupal\taxonomy\Term $term) {
-  $term->foo = 'bar';
-}
-
-/**
- * Act on taxonomy terms when inserted.
- *
- * Modules implementing this hook can act on the term object when saved to
- * the database.
- *
- * @param \Drupal\taxonomy\Term $term
- *   A taxonomy term entity.
- */
-function hook_taxonomy_term_insert(Drupal\taxonomy\Term $term) {
-  db_insert('mytable')
-    ->fields(array(
-      'tid' => $term->id(),
-      'foo' => $term->foo,
-    ))
-    ->execute();
-}
-
-/**
- * Act on taxonomy terms when updated.
- *
- * Modules implementing this hook can act on the term object when updated.
- *
- * @param \Drupal\taxonomy\Term $term
- *   A taxonomy term entity.
- */
-function hook_taxonomy_term_update(Drupal\taxonomy\Term $term) {
-  db_update('mytable')
-    ->fields(array('foo' => $term->foo))
-    ->condition('tid', $term->id())
-    ->execute();
-}
-
-/**
- * Act before taxonomy term deletion.
- *
- * This hook is invoked from taxonomy term deletion before field values are
- * deleted and before the term is actually removed from the database.
- *
- * @param \Drupal\taxonomy\Term $term
- *   The taxonomy term entity that is about to be deleted.
- */
-function hook_taxonomy_term_predelete(Drupal\taxonomy\Term $term) {
-  db_delete('mytable_index')
-    ->condition('tid', $term->id())
-    ->execute();
-}
-
-/**
- * Respond to taxonomy term deletion.
- *
- * This hook is invoked from taxonomy term deletion after field values are
- * deleted and after the term has been removed from the database.
- *
- * @param \Drupal\taxonomy\Term $term
- *   The taxonomy term entity that has been deleted.
- */
-function hook_taxonomy_term_delete(Drupal\taxonomy\Term $term) {
-  db_delete('mytable')
-    ->condition('tid', $term->id())
-    ->execute();
-}
-
-/**
- * Act on a taxonomy term that is being assembled before rendering.
- *
- * The module may add elements to a taxonomy term's renderable array array prior
- * to rendering.
-
- * @param array &$build
- *   A renderable array representing the taxonomy term content.
- * @param \Drupal\taxonomy\Entity\Term $term
- *   The term that is being assembled for rendering.
- * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
- *   The entity view display holding the display options configured for the term
- *   components.
- * @param $view_mode
- *   The $view_mode parameter from taxonomy_term_view().
- * @param $langcode
- *   The language code used for rendering.
- *
- * @see hook_entity_view()
- */
-function hook_taxonomy_term_view(array &$build, \Drupal\taxonomy\Entity\Term $term, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, $view_mode, $langcode) {
-  // Only do the extra work if the component is configured to be displayed.
-  // This assumes a 'mymodule_addition' extra field has been defined for the
-  // vocabulary in hook_entity_extra_field_info().
-  if ($display->getComponent('mymodule_addition')) {
-    $build['mymodule_addition'] = array(
-      '#markup' => mymodule_addition($term),
-      '#theme' => 'mymodule_my_additional_field',
-    );
-  }
-}
-
-/**
- * Alter the results of taxonomy_term_view().
- *
- * This hook is called after the content has been assembled in a structured
- * array and may be used for doing processing which requires that the complete
- * taxonomy term content structure has been built.
- *
- * If the module wishes to act on the rendered HTML of the term rather than the
- * structured content array, it may use this hook to add a #post_render
- * callback. Alternatively, it could also implement
- * hook_preprocess_HOOK() for taxonomy-term.html.twig. See drupal_render() and
- * _theme() documentation respectively for details.
- *
- * @param array &$build
- *   A renderable array representing the taxonomy term content.
- * @param \Drupal\taxonomy\Entity\Term $term
- *   The taxonomy term being rendered.
- * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
- *   The entity view display holding the display options configured for the term
- *   components.
- *
- * @see hook_entity_view_alter()
- */
-function hook_taxonomy_term_view_alter(array &$build, \Drupal\taxonomy\Entity\Term $term, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display) {
-  if ($build['#view_mode'] == 'full' && isset($build['an_additional_field'])) {
-    // Change its weight.
-    $build['an_additional_field']['#weight'] = -10;
-  }
-
-  // Add a #post_render callback to act on the rendered HTML of the term.
-  $build['#post_render'][] = 'my_module_taxonomy_term_post_render';
-}
-
-/**
- * @} End of "addtogroup hooks".
- */
diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module
index 0d9d7370cefb..56ec5149c5ae 100644
--- a/core/modules/taxonomy/taxonomy.module
+++ b/core/modules/taxonomy/taxonomy.module
@@ -746,7 +746,7 @@ function taxonomy_autocomplete_validate($element, &$form_state) {
  */
 
 /**
- * Implements hook_node_insert().
+ * Implements hook_ENTITY_TYPE_insert() for node entities.
  */
 function taxonomy_node_insert(EntityInterface $node) {
   // Add taxonomy index entries for the node.
@@ -800,7 +800,7 @@ function taxonomy_build_node_index($node) {
 }
 
 /**
- * Implements hook_node_update().
+ * Implements hook_ENTITY_TYPE_update() for node entities.
  */
 function taxonomy_node_update(EntityInterface $node) {
   // Always rebuild the node's taxonomy index entries on node save.
@@ -809,7 +809,7 @@ function taxonomy_node_update(EntityInterface $node) {
 }
 
 /**
- * Implements hook_node_predelete().
+ * Implements hook_ENTITY_TYPE_predelete() for node entities.
  */
 function taxonomy_node_predelete(EntityInterface $node) {
   // Clean up the {taxonomy_index} table when nodes are deleted.
@@ -829,7 +829,7 @@ function taxonomy_delete_node_index(EntityInterface $node) {
 }
 
 /**
- * Implements hook_taxonomy_term_delete().
+ * Implements hook_ENTITY_TYPE_delete() for taxonomy_term entities.
  */
 function taxonomy_taxonomy_term_delete(Term $term) {
   if (\Drupal::config('taxonomy.settings')->get('maintain_index_table')) {
diff --git a/core/modules/toolbar/toolbar.module b/core/modules/toolbar/toolbar.module
index a8b4f0815c96..83917807c614 100644
--- a/core/modules/toolbar/toolbar.module
+++ b/core/modules/toolbar/toolbar.module
@@ -541,7 +541,7 @@ function toolbar_modules_uninstalled($modules) {
 }
 
 /**
- * Implements hook_ENTITY_TYPE_update().
+ * Implements hook_ENTITY_TYPE_update() for menu_link entities.
  */
 function toolbar_menu_link_update(MenuLinkInterface $menu_link) {
   if ($menu_link->menu_name === 'admin') {
@@ -550,14 +550,14 @@ function toolbar_menu_link_update(MenuLinkInterface $menu_link) {
 }
 
 /**
- * Implements hook_ENTITY_TYPE_update().
+ * Implements hook_ENTITY_TYPE_update() for user entities.
  */
 function toolbar_user_update(UserInterface $user) {
   _toolbar_clear_user_cache($user->id());
 }
 
 /**
- * Implements hook_ENTITY_TYPE_update().
+ * Implements hook_ENTITY_TYPE_update() for user_role entities.
  */
 function toolbar_user_role_update(RoleInterface $role) {
   _toolbar_clear_user_cache();
diff --git a/core/modules/tour/tour.api.php b/core/modules/tour/tour.api.php
index 6537cc7c19ac..04049f5c2daf 100644
--- a/core/modules/tour/tour.api.php
+++ b/core/modules/tour/tour.api.php
@@ -5,6 +5,11 @@
  * Describes API functions for tour module.
  */
 
+/**
+ * @addtogroup hooks
+ * @{
+ */
+
 /**
  * Allow modules to alter tour items before render.
  *
@@ -37,52 +42,5 @@ function hook_tour_tips_info_alter(&$info) {
 }
 
 /**
- * Act on tour objects when loaded.
- *
- * @param array $entities
- *   An array of \Drupal\tour\Entity\Tour objects, indexed by id.
- */
-function hook_tour_load($entities) {
-  if (isset($entities['tour-entity-create-test-en'])) {
-    $entities['tour-entity-create-test-en']->loaded = 'Load hooks work';
-  }
-}
-
-/**
- * Act on a tour being inserted or updated.
- *
- * This hook is invoked before the tour object is saved to configuration.
- *
- * @param \Drupal\tour\Entity\Tour $entity
- *   The tour object.
- *
- * @see hook_tour_insert()
- * @see hook_tour_update()
- */
-function hook_tour_presave($entity) {
-  if ($entity->id() == 'tour-entity-create-test-en') {
-    $entity->set('label', $entity->label() . ' alter');
-  }
-}
-
-/**
- * Respond to creation of a new tour.
- *
- * @param \Drupal\tour\Entity\Tour $entity
- *   The tour object being inserted.
- */
-function hook_tour_insert($entity) {
-  \Drupal::service('plugin.manager.tour.tip')->clearCachedDefinitions();
-  \Drupal\Core\Cache\Cache::deleteTags(array('tour_items'));
-}
-
-/**
- * Respond to updates to a tour object.
- *
- * @param \Drupal\tour\Entity\Tour $entity
- *   The tour object being updated.
+ * @} End of "addtogroup hooks".
  */
-function hook_tour_update($entity) {
-  \Drupal::service('plugin.manager.tour.tip')->clearCachedDefinitions();
-  \Drupal\Core\Cache\Cache::deleteTags(array('tour_items'));
-}
diff --git a/core/modules/tour/tour.module b/core/modules/tour/tour.module
index 17001e8d34d4..001acaf7d9b4 100644
--- a/core/modules/tour/tour.module
+++ b/core/modules/tour/tour.module
@@ -103,14 +103,14 @@ function tour_preprocess_page(&$variables) {
 }
 
 /**
- * Implements hook_tour_insert().
+ * Implements hook_ENTITY_TYPE_insert() for tour entities.
  */
 function tour_tour_insert($entity) {
   \Drupal::service('plugin.manager.tour.tip')->clearCachedDefinitions();
 }
 
 /**
- * Implements hook_tour_update().
+ * Implements hook_ENTITY_TYPE_update() for tour entities.
  */
 function tour_tour_update($entity) {
   \Drupal::service('plugin.manager.tour.tip')->clearCachedDefinitions();
diff --git a/core/modules/tracker/tracker.module b/core/modules/tracker/tracker.module
index d1c911b33b72..1c41d50cd782 100644
--- a/core/modules/tracker/tracker.module
+++ b/core/modules/tracker/tracker.module
@@ -154,7 +154,7 @@ function _tracker_user_access($account) {
 }
 
 /**
- * Implements hook_node_insert().
+ * Implements hook_ENTITY_TYPE_insert() for node entities.
  *
  * Adds new tracking information for this node since it's new.
  */
@@ -163,7 +163,7 @@ function tracker_node_insert(NodeInterface $node, $arg = 0) {
 }
 
 /**
- * Implements hook_node_update().
+ * Implements hook_ENTITY_TYPE_update() for node entities.
  *
  * Adds tracking information for this node since it's been updated.
  */
@@ -172,7 +172,7 @@ function tracker_node_update(NodeInterface $node, $arg = 0) {
 }
 
 /**
- * Implements hook_node_predelete().
+ * Implements hook_ENTITY_TYPE_predelete() for node entities.
  *
  * Deletes tracking information for a node.
  */
@@ -186,7 +186,7 @@ function tracker_node_predelete(EntityInterface $node, $arg = 0) {
 }
 
 /**
- * Implements hook_comment_update().
+ * Implements hook_ENTITY_TYPE_update() for comment entities.
  */
 function tracker_comment_update(CommentInterface $comment) {
   if ($comment->getCommentedEntityTypeId() == 'node') {
@@ -200,7 +200,7 @@ function tracker_comment_update(CommentInterface $comment) {
 }
 
 /**
- * Implements hook_comment_insert().
+ * Implements hook_ENTITY_TYPE_insert() for comment entities.
  */
 function tracker_comment_insert(CommentInterface $comment) {
   if ($comment->getCommentedEntityTypeId() == 'node' && $comment->isPublished()) {
@@ -209,7 +209,7 @@ function tracker_comment_insert(CommentInterface $comment) {
 }
 
 /**
- * Implements hook_comment_delete().
+ * Implements hook_ENTITY_TYPE_delete() for comment entities.
  */
 function tracker_comment_delete(CommentInterface $comment) {
   if ($comment->getCommentedEntityTypeId() == 'node') {
diff --git a/core/modules/user/user.api.php b/core/modules/user/user.api.php
index 7b5313eb4dab..34e9f7f06fb0 100644
--- a/core/modules/user/user.api.php
+++ b/core/modules/user/user.api.php
@@ -12,81 +12,6 @@
  * @{
  */
 
-/**
- * Act on a newly created user.
- *
- * This hook runs after a new user object has just been instantiated. It can be
- * used to set initial values, e.g. to provide defaults.
- *
- * @param \Drupal\user\UserInterface $user
- *   The user object.
- */
-function hook_user_create(\Drupal\user\Entity\User $user) {
-  if (!isset($user->foo)) {
-    $user->foo = 'some_initial_value';
-  }
-}
-
-/**
- * Act on user objects when loaded from the database.
- *
- * Due to the static cache in user_load_multiple() you should not use this
- * hook to modify the user properties returned by the {users} table itself
- * since this may result in unreliable results when loading from cache.
- *
- * @param $users
- *   An array of user objects, indexed by uid.
- *
- * @see user_load_multiple()
- * @see profile_user_load()
- */
-function hook_user_load($users) {
-  $result = db_query('SELECT uid, foo FROM {my_table} WHERE uid IN (:uids)', array(':uids' => array_keys($users)));
-  foreach ($result as $record) {
-    $users[$record->uid]->foo = $record->foo;
-  }
-}
-
-/**
- * Act before user deletion.
- *
- * This hook is invoked from user_delete_multiple() before field values are
- * deleted and before the user is actually removed from the database.
- *
- * Modules should additionally implement hook_user_cancel() to process stored
- * user data for other account cancellation methods.
- *
- * @param $account
- *   The account that is about to be deleted.
- *
- * @see hook_user_delete()
- * @see user_delete_multiple()
- */
-function hook_user_predelete($account) {
-  db_delete('mytable')
-    ->condition('uid', $account->id())
-    ->execute();
-}
-
-/**
- * Respond to user deletion.
- *
- * This hook is invoked from user_delete_multiple() after field values are
- * deleted and after the user has been removed from the database.
- *
- * Modules should additionally implement hook_user_cancel() to process stored
- * user data for other account cancellation methods.
- *
- * @param $account
- *   The account that has been deleted.
- *
- * @see hook_user_predelete()
- * @see user_delete_multiple()
- */
-function hook_user_delete($account) {
-  drupal_set_message(t('User: @name has been deleted.', array('@name' => $account->getUsername())));
-}
-
 /**
  * Act on user account cancellations.
  *
@@ -97,8 +22,8 @@ function hook_user_delete($account) {
  * Modules may add further methods via hook_user_cancel_methods_alter().
  *
  * This hook is NOT invoked for the 'user_cancel_delete' account cancellation
- * method. To react to that method, implement hook_user_predelete() or
- * hook_user_delete() instead.
+ * method. To react to that method, implement hook_ENTITY_TYPE_predelete() or
+ * hook_ENTITY_TYPE_delete() for user entities instead.
  *
  * Expensive operations should be added to the global account cancellation batch
  * by using batch_set().
@@ -201,78 +126,6 @@ function hook_user_format_name_alter(&$name, $account) {
   }
 }
 
-/**
- * Act on a user account being inserted or updated.
- *
- * This hook is invoked before the user account is saved to the database.
- *
- * @param $account
- *   The user account object.
- *
- * @see hook_user_insert()
- * @see hook_user_update()
- */
-function hook_user_presave($account) {
-  // Ensure that our value is an array.
-  if (isset($account->mymodule_foo)) {
-    $account->mymodule_foo = (array) $account->mymodule_foo;
-  }
-}
-
-/**
- * Respond to creation of a new user account.
- *
- * Note that when this hook is invoked, the changes have not yet been written to
- * the database, because a database transaction is still in progress. The
- * transaction is not finalized until the insert operation is entirely completed
- * and \Drupal\user\DataStorage::save() goes out of scope. You should
- * not rely on data in the database at this time as it is not updated yet. You
- * should also note that any write/update database queries executed from this hook
- * are also not committed immediately. Check \Drupal\user\DataStorage::save()
- * and db_transaction() for more info.
- *
- * @param $account
- *   The user account object.
- *
- * @see hook_user_presave()
- * @see hook_user_update()
- */
-function hook_user_insert($account) {
-  db_insert('user_changes')
-    ->fields(array(
-      'uid' => $account->id(),
-      'created' => time(),
-    ))
-    ->execute();
-}
-
-/**
- * Respond to updates to a user account.
- *
- * Note that when this hook is invoked, the changes have not yet been written to
- * the database, because a database transaction is still in progress. The
- * transaction is not finalized until the update operation is entirely completed
- * and \Drupal\user\DataStorage::save() goes out of scope. You should not
- * rely on data in the database at this time as it is not updated yet. You should
- * also note that any write/update database queries executed from this hook are
- * also not committed immediately. Check \Drupal\user\DataStorage::save()
- * and db_transaction() for more info.
- *
- * @param $account
- *   The user account object.
- *
- * @see hook_user_presave()
- * @see hook_user_insert()
- */
-function hook_user_update($account) {
-  db_insert('user_changes')
-    ->fields(array(
-      'uid' => $account->id(),
-      'changed' => time(),
-    ))
-    ->execute();
-}
-
 /**
  * The user just logged in.
  *
@@ -302,153 +155,6 @@ function hook_user_logout($account) {
     ->execute();
 }
 
-/**
- * The user's account information is being displayed.
- *
- * The module should format its custom additions for display and add them to the
- * $build array.
- *
- * @param array &$build
- *   A renderable array representing the user content.
- * @param \Drupal\user\UserInterface $account
- *   The user object on which the operation is being performed.
- * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
- *   The entity view display holding the display options configured for the user
- *   components.
- * @param $view_mode
- *   View mode, e.g. 'full'.
- * @param $langcode
- *   The language code used for rendering.
- *
- * @see hook_user_view_alter()
- * @see hook_entity_view()
- */
-function hook_user_view(array &$build, \Drupal\user\UserInterface $account, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, $view_mode, $langcode) {
-  // Only do the extra work if the component is configured to be displayed.
-  // This assumes a 'mymodule_addition' extra field has been defined for the
-  // user entity type in hook_entity_extra_field_info().
-  if ($display->getComponent('mymodule_addition')) {
-    $build['mymodule_addition'] = array(
-      '#markup' => mymodule_addition($account),
-      '#theme' => 'mymodule_my_additional_field',
-    );
-  }
-}
-
-/**
- * The user was built; the module may modify the structured content.
- *
- * This hook is called after the content has been assembled in a structured array
- * and may be used for doing processing which requires that the complete user
- * content structure has been built.
- *
- * If the module wishes to act on the rendered HTML of the user rather than the
- * structured content array, it may use this hook to add a #post_render callback.
- * Alternatively, it could also implement hook_preprocess_HOOK() for
- * user.html.twig. See drupal_render() and _theme() documentation
- * respectively for details.
- *
- * @param array &$build
- *   A renderable array representing the user.
- * @param \Drupal\user\UserInterface $account
- *   The user account being rendered.
- * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
- *   The entity view display holding the display options configured for the user
- *   components.
- *
- * @see user_view()
- * @see hook_entity_view_alter()
- */
-function hook_user_view_alter(array &$build, \Drupal\user\UserInterface $account, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display) {
-  // Check for the existence of a field added by another module.
-  if (isset($build['an_additional_field'])) {
-    // Change its weight.
-    $build['an_additional_field']['#weight'] = -10;
-  }
-
-  // Add a #post_render callback to act on the rendered HTML of the user.
-  $build['#post_render'][] = 'my_module_user_post_render';
-}
-
-/**
- * Act on a user role being inserted or updated.
- *
- * Modules implementing this hook can act on the user role object before
- * it has been saved to the database.
- *
- * @param $role
- *   A user role object.
- *
- * @see hook_user_role_insert()
- * @see hook_user_role_update()
- */
-function hook_user_role_presave($role) {
-  // Set a UUID for the user role if it doesn't already exist
-  if (empty($role->uuid)) {
-    $role->uuid = uuid_uuid();
-  }
-}
-
-/**
- * Respond to creation of a new user role.
- *
- * Modules implementing this hook can act on the user role object when saved to
- * the database. It's recommended that you implement this hook if your module
- * adds additional data to user roles object. The module should save its custom
- * additions to the database.
- *
- * @param $role
- *   A user role object.
- */
-function hook_user_role_insert($role) {
-  // Save extra fields provided by the module to user roles.
-  db_insert('my_module_table')
-    ->fields(array(
-      'rid' => $role->id(),
-      'role_description' => $role->description,
-    ))
-    ->execute();
-}
-
-/**
- * Respond to updates to a user role.
- *
- * Modules implementing this hook can act on the user role object when updated.
- * It's recommended that you implement this hook if your module adds additional
- * data to user roles object. The module should save its custom additions to
- * the database.
- *
- * @param $role
- *   A user role object.
- */
-function hook_user_role_update($role) {
-  // Save extra fields provided by the module to user roles.
-  db_merge('my_module_table')
-    ->key('rid', $role->id())
-    ->fields(array(
-      'role_description' => $role->description
-    ))
-    ->execute();
-}
-
-/**
- * Respond to user role deletion.
- *
- * This hook allows you act when a user role has been deleted.
- * If your module stores references to roles, it's recommended that you
- * implement this hook and delete existing instances of the deleted role
- * in your module database tables.
- *
- * @param $role
- *   The $role object being deleted.
- */
-function hook_user_role_delete($role) {
-  // Delete existing instances of the deleted role.
-  db_delete('my_module_table')
-    ->condition('rid', $role->id())
-    ->execute();
-}
-
 /**
  * @} End of "addtogroup hooks".
  */
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 78d879cb0946..3e84dd6dcbe1 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -494,7 +494,7 @@ function user_permission() {
 }
 
 /**
- * Implements hook_user_view().
+ * Implements hook_ENTITY_TYPE_view() for user entities.
  */
 function user_user_view(array &$build, UserInterface $account, EntityViewDisplayInterface $display) {
   if ($display->getComponent('member_for')) {
@@ -736,8 +736,9 @@ function user_login_finalize(UserInterface $account) {
     ->updateLastLoginTimestamp($account);
 
   // Regenerate the session ID to prevent against session fixation attacks.
-  // This is called before hook_user in case one of those functions fails
-  // or incorrectly does a redirect which would leave the old session in place.
+  // This is called before hook_user_login() in case one of those functions
+  // fails or incorrectly does a redirect which would leave the old session
+  // in place.
   \Drupal::service('session_manager')->regenerate();
 
   \Drupal::moduleHandler()->invokeAll('user_login', array($account));
@@ -871,8 +872,9 @@ function user_cancel($edit, $uid, $method) {
   batch_set($batch);
 
   // When the 'user_cancel_delete' method is used, user_delete() is called,
-  // which invokes hook_user_predelete() and hook_user_delete(). Modules
-  // should use those hooks to respond to the account deletion.
+  // which invokes hook_ENTITY_TYPE_predelete() and hook_ENTITY_TYPE_delete()
+  // for the user entity. Modules should use those hooks to respond to the
+  // account deletion.
   if ($method != 'user_cancel_delete') {
     // Allow modules to add further sets to this batch.
     \Drupal::moduleHandler()->invokeAll('user_cancel', array($edit, $account, $method));
@@ -1029,8 +1031,8 @@ function user_delete($uid) {
  * @param $uids
  *   An array of user IDs.
  *
- * @see hook_user_predelete()
- * @see hook_user_delete()
+ * @see hook_ENTITY_TYPE_predelete()
+ * @see hook_ENTITY_TYPE_delete()
  */
 function user_delete_multiple(array $uids) {
   entity_delete_multiple('user', $uids);
@@ -1154,7 +1156,7 @@ function user_role_names($membersonly = FALSE, $permission = NULL) {
 }
 
 /**
- * Implements hook_user_role_insert().
+ * Implements hook_ENTITY_TYPE_insert() for user_role entities.
  */
 function user_user_role_insert(RoleInterface $role) {
   // Ignore the authenticated and anonymous roles or the role is being synced.
@@ -1191,7 +1193,7 @@ function user_user_role_insert(RoleInterface $role) {
 }
 
 /**
- * Implements hook_user_role_delete().
+ * Implements hook_ENTITY_TYPE_delete() for user_role entities.
  */
 function user_user_role_delete(RoleInterface $role) {
   // Ignore the authenticated and anonymous roles or the role is being synced.
-- 
GitLab