diff --git a/core/includes/entity.api.php b/core/includes/entity.api.php
index a5099265fc708001e545ba52a4b33535c9441dd6..c12e4db94a67ddbc4d92403faf81ecc049fcca34 100644
--- a/core/includes/entity.api.php
+++ b/core/includes/entity.api.php
@@ -11,22 +11,43 @@
  */
 
 /**
- * Alter the entity type definition.
+ * Add to entity type definitions.
+ *
+ * Modules may implement this hook to add information to defined entity types.
+ *
+ * @param array $entity_info
+ *   An associative array of all entity type definitions, keyed by the entity
+ *   type name. Passed by reference.
+ *
+ * @see \Drupal\Core\Entity\Entity
+ * @see \Drupal\Core\Entity\EntityManager
+ * @see entity_get_info()
+ */
+function hook_entity_info(&$entity_info) {
+  // Add the 'Print' view mode for nodes.
+  $entity_info['node']['view_modes']['print'] = array(
+    'label' => t('Print'),
+    'custom_settings' => FALSE,
+  );
+}
+
+/**
+ * Alter the entity type definitions.
  *
  * Modules may implement this hook to alter the information that defines an
- * entity. All properties that are available in
+ * entity type. All properties that are available in
  * \Drupal\Core\Entity\EntityManager can be altered here.
  *
+ * Do not use this hook to add information to entity types. Use
+ * hook_entity_info() for that instead.
+ *
  * @param array $entity_info
  *   An associative array of all entity type definitions, keyed by the entity
- *   type name.
+ *   type name. Passed by reference.
  *
  * @see \Drupal\Core\Entity\Entity
  * @see \Drupal\Core\Entity\EntityManager
  * @see entity_get_info()
- *
- * @todo Allow a module to add its bundles and view modes before other modules
- *   alter the definition.
  */
 function hook_entity_info_alter(&$entity_info) {
   // Set the controller class for nodes to an alternate implementation of the
diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php
index a75dc441fa1e277ca6162bd813a9505c09180713..e34adb673d3bc9360e9ea2201d20dd9619325bae 100644
--- a/core/lib/Drupal/Core/Entity/EntityManager.php
+++ b/core/lib/Drupal/Core/Entity/EntityManager.php
@@ -11,6 +11,7 @@
 use Drupal\Component\Plugin\Factory\DefaultFactory;
 use Drupal\Core\Plugin\Discovery\AlterDecorator;
 use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
+use Drupal\Core\Plugin\Discovery\InfoHookDecorator;
 use Drupal\Core\Cache\CacheBackendInterface;
 
 /**
@@ -222,7 +223,7 @@ class EntityManager extends PluginManagerBase {
    */
   public function __construct() {
     // Allow the plugin definition to be altered by hook_entity_info_alter().
-    $this->discovery = new AlterDecorator(new AnnotatedClassDiscovery('Core', 'Entity'), 'entity_info');
+    $this->discovery = new AlterDecorator(new InfoHookDecorator(new AnnotatedClassDiscovery('Core', 'Entity'), 'entity_info'), 'entity_info');
     $this->factory = new DefaultFactory($this);
 
     // Entity type plugins includes translated strings, so each language is
diff --git a/core/lib/Drupal/Core/Plugin/Discovery/AlterDecorator.php b/core/lib/Drupal/Core/Plugin/Discovery/AlterDecorator.php
index d4ce40b08314e4e0f77b0e786de97cb04ce54539..8bcee3f2758d2142b6199103194c66e03d1c479b 100644
--- a/core/lib/Drupal/Core/Plugin/Discovery/AlterDecorator.php
+++ b/core/lib/Drupal/Core/Plugin/Discovery/AlterDecorator.php
@@ -35,7 +35,7 @@ class AlterDecorator implements DiscoveryInterface {
    * @param Drupal\Component\Plugin\Discovery\DiscoveryInterface $decorated
    *   The object implementing DiscoveryInterface that is being decorated.
    * @param string $hook
-   *   The name of the alter hook that will be implemented by this discovery instance.
+   *   The name of the alter hook that will be used by this discovery instance.
    */
   public function __construct(DiscoveryInterface $decorated, $hook) {
     $this->decorated = $decorated;
diff --git a/core/lib/Drupal/Core/Plugin/Discovery/InfoHookDecorator.php b/core/lib/Drupal/Core/Plugin/Discovery/InfoHookDecorator.php
new file mode 100644
index 0000000000000000000000000000000000000000..7ba8913bf9cea0342802861a7444244221323311
--- /dev/null
+++ b/core/lib/Drupal/Core/Plugin/Discovery/InfoHookDecorator.php
@@ -0,0 +1,71 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\Plugin\Discovery\InfoHookDecorator.
+ */
+
+namespace Drupal\Core\Plugin\Discovery;
+
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+
+/**
+ * Allows info hook implementations to enhance discovered plugin definitions.
+ */
+class InfoHookDecorator implements DiscoveryInterface {
+
+  /**
+   * The Discovery object being decorated.
+   *
+   * @var Drupal\Component\Plugin\Discovery\DiscoveryInterface
+   */
+  protected $decorated;
+
+  /**
+   * The name of the info hook that will be implemented by this discovery instance.
+   *
+   * @var string
+   */
+  protected $hook;
+
+  /**
+   * Constructs a InfoHookDecorator object.
+   *
+   * @param Drupal\Component\Plugin\Discovery\DiscoveryInterface $decorated
+   *   The object implementing DiscoveryInterface that is being decorated.
+   * @param string $hook
+   *   The name of the info hook to be invoked by this discovery instance.
+   */
+  public function __construct(DiscoveryInterface $decorated, $hook) {
+    $this->decorated = $decorated;
+    $this->hook = $hook;
+  }
+
+  /**
+   * Implements Drupal\Component\Plugin\Discovery\DiscoveryInterface::getDefinition().
+   */
+  public function getDefinition($plugin_id) {
+    $definitions = $this->getDefinitions();
+    return isset($definitions[$plugin_id]) ? $definitions[$plugin_id] : NULL;
+  }
+
+  /**
+   * Implements Drupal\Component\Plugin\Discovery\DiscoveryInterface::getDefinitions().
+   */
+  public function getDefinitions() {
+    $definitions = $this->decorated->getDefinitions();
+    foreach (module_implements($this->hook) as $module) {
+      $function = $module . '_' . $this->hook;
+      $function($definitions);
+    }
+    return $definitions;
+  }
+
+  /**
+   * Passes through all unknown calls onto the decorated object.
+   */
+  public function __call($method, $args) {
+    return call_user_func_array(array($this->decorated, $method), $args);
+  }
+
+}
diff --git a/core/modules/book/book.module b/core/modules/book/book.module
index 4c514af3432aeb07b815b4ec34a24ee44db6fcfd..062097aeaa8ff626d0107664162f96131b1f6445 100644
--- a/core/modules/book/book.module
+++ b/core/modules/book/book.module
@@ -246,9 +246,9 @@ function book_admin_paths() {
 }
 
 /**
- * Implements hook_entity_info_alter().
+ * Implements hook_entity_info().
  */
-function book_entity_info_alter(&$info) {
+function book_entity_info(&$info) {
   // Add the 'Print' view mode for nodes.
   $info['node']['view_modes']['print'] = array(
     'label' => t('Print'),
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index 87c179891454b35bf1d3537649f3a4ca31ede6ac..24f48add80941eeaeb8841bfda5d00f99e1435ae 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -98,9 +98,9 @@ function comment_help($path, $arg) {
 }
 
 /**
- * Implements hook_entity_info_alter().
+ * Implements hook_entity_info().
  */
-function comment_entity_info_alter(&$info) {
+function comment_entity_info(&$info) {
   foreach (node_type_get_names() as $type => $name) {
     $info['comment']['bundles']['comment_node_' . $type] = array(
       'label' => t('@node_type comment', array('@node_type' => $name)),
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index a6a64aeb212f85371c0ca0febf53b48dc46eb295..e6251abedfcd270d0849733b1fb4e825d535ecf6 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -192,9 +192,9 @@ function node_cron() {
 }
 
 /**
- * Implements hook_entity_info_alter().
+ * Implements hook_entity_info().
  */
-function node_entity_info_alter(&$info) {
+function node_entity_info(&$info) {
   // Add a translation handler for fields if the language module is enabled.
   if (module_exists('language')) {
     $info['node']['translation']['node'] = TRUE;
diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module
index 8da637f1ace011434c627d996685869a0f28aa86..d8ea5b79c40fbc7a1a49faff26ab5f6ba362478b 100644
--- a/core/modules/taxonomy/taxonomy.module
+++ b/core/modules/taxonomy/taxonomy.module
@@ -106,9 +106,9 @@ function taxonomy_permission() {
 }
 
 /**
- * Implements hook_entity_info_alter().
+ * Implements hook_entity_info().
  */
-function taxonomy_entity_info_alter(&$info) {
+function taxonomy_entity_info(&$info) {
   foreach (taxonomy_vocabulary_get_names() as $machine_name => $vocabulary) {
     $info['taxonomy_term']['bundles'][$machine_name] = array(
       'label' => $vocabulary->name,