diff --git a/core/includes/entity.api.php b/core/includes/entity.api.php
index fc1beb0..99049f8 100644
--- a/core/includes/entity.api.php
+++ b/core/includes/entity.api.php
@@ -454,6 +454,10 @@ function hook_entity_display_alter(\Drupal\entity\Plugin\Core\Entity\EntityDispl
 /**
  * Act on an entity object about to be shown on 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 add/edit form.
  * @param array $form_state
@@ -461,7 +465,7 @@ function hook_entity_display_alter(\Drupal\entity\Plugin\Core\Entity\EntityDispl
  *
  * @see \Drupal\Core\Entity\EntityFormController::prepareEntity()
  */
-function hook_entity_prepare(\Drupal\Core\Entity\EntityInterface $entity, array &$form_state) {
+function hook_entity_prepare_form(\Drupal\Core\Entity\EntityInterface $entity, array &$form_state) {
   if ($form_state['controller']->getOperation() == 'default') {
     $entity->label->value = 'Altered label';
     $form_state['mymodule']['label_altered'] = TRUE;
diff --git a/core/lib/Drupal/Core/Entity/EntityFormController.php b/core/lib/Drupal/Core/Entity/EntityFormController.php
index 4d7ac52..a356878 100644
--- a/core/lib/Drupal/Core/Entity/EntityFormController.php
+++ b/core/lib/Drupal/Core/Entity/EntityFormController.php
@@ -120,7 +120,7 @@ protected function init(array &$form_state) {
     // Add the controller to the form state so it can be easily accessed by
     // module-provided form handlers there.
     $form_state['controller'] = $this;
-    $this->prepareEntity();
+    $this->prepareEntity($form_state);
 
     // @todo Allow the usage of different form modes by exposing a hook and the
     // UI for them.
@@ -414,12 +414,19 @@ public function setEntity(EntityInterface $entity) {
 
   /**
    * Prepares the entity object before the form is built first.
+   *
+   * This can be used to fill in a default values. It then invokes
+   * hook_entity_prepare_form() and hook_ENTITY_TYPE_prepare_form() on all
+   * modules.
+   *
+   * @param array $form_state
+   *   An associative array containing the current state of the form.
    */
-  protected function prepareEntity() {
+  protected function prepareEntity(array &$form_state) {
     $handler = \Drupal::moduleHandler();
-    $args = array($this->entity, $this);
-    $handler->invokeAll('entity_prepare', $args);
-    $handler->invokeAll($this->entity->entityType() . '_prepare', $args);
+    $args = array($this->entity, &$form_state);
+    $handler->invokeAll('entity_prepare_form', $args);
+    $handler->invokeAll($this->entity->entityType() . '_prepare_form', $args);
   }
 
   /**
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockFormController.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockFormController.php
index 2457d97..777f695 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockFormController.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockFormController.php
@@ -24,7 +24,7 @@ class CustomBlockFormController extends EntityFormControllerNG {
    * Fills in a few default values, and then invokes hook_custom_block_prepare()
    * on all modules.
    */
-  protected function prepareEntity() {
+  protected function prepareEntity(array &$form_state) {
     $block = $this->entity;
     // Set up default values, if required.
     $block_type = entity_load('custom_block_type', $block->type->value);
@@ -35,7 +35,7 @@ protected function prepareEntity() {
     // Always use the default revision setting.
     $block->setNewRevision($block_type->revision);
 
-    module_invoke_all('custom_block_prepare', $block);
+    parent::prepareEntity($form_state);
   }
 
   /**
diff --git a/core/modules/book/book.module b/core/modules/book/book.module
index 1fe04c8..bf8ecdd 100644
--- a/core/modules/book/book.module
+++ b/core/modules/book/book.module
@@ -874,9 +874,9 @@ function book_node_predelete(EntityInterface $node) {
 }
 
 /**
- * Implements hook_node_prepare().
+ * Implements hook_node_prepare_form().
  */
-function book_node_prepare(EntityInterface $node) {
+function book_node_prepare_form(EntityInterface $node, array &$form_state) {
   // Prepare defaults for the add/edit form.
   if (empty($node->book) && (user_access('add content to books') || user_access('administer book outlines'))) {
     $node->book = array();
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index b0f71f1..2c898d2 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -1177,9 +1177,9 @@ function comment_node_load($nodes, $types) {
 }
 
 /**
- * Implements hook_node_prepare().
+ * Implements hook_node_prepare_form().
  */
-function comment_node_prepare(EntityInterface $node) {
+function comment_node_prepare_form(EntityInterface $node, array &$form_state) {
   if (!isset($node->comment)) {
     $node->comment = variable_get("comment_$node->type", COMMENT_NODE_OPEN);
   }
diff --git a/core/modules/datetime/datetime.module b/core/modules/datetime/datetime.module
index 88e6a77..700cdc9 100644
--- a/core/modules/datetime/datetime.module
+++ b/core/modules/datetime/datetime.module
@@ -1148,9 +1148,9 @@ function datetime_form_node_form_alter(&$form, &$form_state, $form_id) {
 }
 
 /**
- * Implements hook_node_prepare().
+ * Implements hook_node_prepare_form().
  */
-function datetime_node_prepare(NodeInterface $node) {
+function datetime_node_prepare_form(NodeInterface $node, array &$form_state) {
   // Prepare the 'Authored on' date to use datetime.
   $node->date = new DrupalDateTime($node->created);
 }
diff --git a/core/modules/menu/menu.module b/core/modules/menu/menu.module
index 68c3125..afed76d 100644
--- a/core/modules/menu/menu.module
+++ b/core/modules/menu/menu.module
@@ -489,9 +489,9 @@ function menu_node_predelete(EntityInterface $node) {
 }
 
 /**
- * Implements hook_node_prepare().
+ * Implements hook_node_prepare_form().
  */
-function menu_node_prepare(EntityInterface $node) {
+function menu_node_prepare_form(EntityInterface $node, array &$form_state) {
   if (empty($node->menu)) {
     // Prepare the node for the edit form so that $node->menu always exists.
     $menu_name = strtok(variable_get('menu_parent_' . $node->type, 'main:0'), ':');
diff --git a/core/modules/node/lib/Drupal/node/NodeFormController.php b/core/modules/node/lib/Drupal/node/NodeFormController.php
index 71da378..c617d87 100644
--- a/core/modules/node/lib/Drupal/node/NodeFormController.php
+++ b/core/modules/node/lib/Drupal/node/NodeFormController.php
@@ -18,14 +18,9 @@
 class NodeFormController extends EntityFormController {
 
   /**
-   * Prepares the node object.
-   *
-   * Fills in a few default values, and then invokes hook_node_prepare() on all
-   * modules.
-   *
-   * Overrides Drupal\Core\Entity\EntityFormController::prepareEntity().
+   * {@inheritdoc}
    */
-  protected function prepareEntity() {
+  protected function prepareEntity(array &$form_state) {
     $node = $this->entity;
     // Set up default values, if required.
     $node_options = variable_get('node_options_' . $node->type, array('status', 'promote'));
@@ -49,7 +44,7 @@ protected function prepareEntity() {
     // Always use the default revision setting.
     $node->setNewRevision(in_array('revision', $node_options));
 
-    parent::prepareEntity();
+    parent::prepareEntity($form_state);
   }
 
   /**
diff --git a/core/modules/node/node.api.php b/core/modules/node/node.api.php
index 5764152..1f022a0 100644
--- a/core/modules/node/node.api.php
+++ b/core/modules/node/node.api.php
@@ -94,7 +94,8 @@
  *   - field_attach_delete_revision()
  * - 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() (all)
+ *   - hook_node_prepare_form() (all)
+ *   - hook_entity_prepare_form() (all)
  *   - field_attach_form()
  * - Validating a node during editing form submit (calling
  *   node_form_validate()):
diff --git a/core/modules/translation/translation.module b/core/modules/translation/translation.module
index 115be1a..61681ea 100644
--- a/core/modules/translation/translation.module
+++ b/core/modules/translation/translation.module
@@ -304,9 +304,9 @@ function translation_node_view(EntityInterface $node, EntityDisplay $display, $v
 }
 
 /**
- * Implements hook_node_prepare().
+ * Implements hook_node_prepare_form().
  */
-function translation_node_prepare(EntityInterface $node) {
+function translation_node_prepare_form(EntityInterface $node) {
   $query = Drupal::request()->query;
   $translation = $query->get('translation');
   $target = $query->get('target');
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/ViewAddFormController.php b/core/modules/views_ui/lib/Drupal/views_ui/ViewAddFormController.php
index 16f023c..638144e 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/ViewAddFormController.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/ViewAddFormController.php
@@ -61,7 +61,7 @@ public function init(array &$form_state) {
   /**
    * Overrides Drupal\Core\Entity\EntityFormController::prepareForm().
    */
-  protected function prepareEntity() {
+  protected function prepareEntity(array &$form_state) {
     // Do not prepare the entity while it is being added.
   }
 
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/ViewCloneFormController.php b/core/modules/views_ui/lib/Drupal/views_ui/ViewCloneFormController.php
index 32ef533..badc926 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/ViewCloneFormController.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/ViewCloneFormController.php
@@ -24,7 +24,7 @@ public function init(array &$form_state) {
   /**
    * Overrides \Drupal\Core\Entity\EntityFormController::prepareForm().
    */
-  protected function prepareEntity() {
+  protected function prepareEntity(array &$form_state) {
     // Do not prepare the entity while it is being added.
   }
 
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/ViewFormControllerBase.php b/core/modules/views_ui/lib/Drupal/views_ui/ViewFormControllerBase.php
index 98637f7..4075c24 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/ViewFormControllerBase.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/ViewFormControllerBase.php
@@ -41,7 +41,7 @@ public function init(array &$form_state) {
   /**
    * Overrides Drupal\Core\Entity\EntityFormController::prepareForm().
    */
-  protected function prepareEntity() {
+  protected function prepareEntity(array &$form_state) {
     // Determine the displays available for editing.
     if ($tabs = $this->getDisplayTabs($this->entity)) {
       // If a display isn't specified, use the first one.
@@ -66,6 +66,8 @@ protected function prepareEntity() {
     elseif ($this->displayID) {
       throw new NotFoundHttpException();
     }
+    // Invoke prepare hooks.
+    parent::prepareEntity($form_state);
   }
 
   /**
