diff --git a/core/includes/entity.api.php b/core/includes/entity.api.php
index e9fb855..58d7f8a 100644
--- a/core/includes/entity.api.php
+++ b/core/includes/entity.api.php
@@ -11,232 +11,65 @@
  */
 
 /**
- * Inform the base system and the Field API about one or more entity types.
- *
- * Inform the system about one or more entity types (i.e., object types that
- * can be loaded via entity_load() and, optionally, to which fields can be
- * attached).
- *
- * @return
- *   An array whose keys are entity type names and whose values identify
- *   properties of those types that the system needs to know about:
- *   - label: The human-readable name of the type.
- *   - entity class: The name of the entity class, defaults to
- *     Drupal\Core\Entity\Entity. The entity class must implement EntityInterface.
- *   - controller class: The name of the class that is used to load the objects.
- *     The class has to implement the
- *     Drupal\Core\Entity\EntityStorageControllerInterface interface. Leave blank
- *     to use the Drupal\Core\Entity\DatabaseStorageController implementation.
- *   - render controller class: The name of the class that is used to render
- *     the entities. Deafaults to Drupal\Core\Entity\EntityRenderController.
- *   - form controller class: An associative array where the keys are the names
- *     of the different form operations (such as creation, editing or deletion)
- *     and the values are the names of the controller classes. To facilitate
- *     supporting the case where an entity form varies only slightly between
- *     different operations, the name of the operation is passed also to the
- *     constructor of the form controller class. This way, one class can be used
- *     for multiple entity forms.
- *   - list controller class: The name of the class that is used to provide
- *     listings of the entity. The class must implement
- *     Drupal\Core\Entity\EntityListControllerInterface. Defaults to
- *     Drupal\Core\Entity\EntityListController.
- *   - base table: (used by Drupal\Core\Entity\DatabaseStorageController) The
- *     name of the entity type's base table.
- *   - static cache: (used by Drupal\Core\Entity\DatabaseStorageController)
- *     FALSE to disable static caching of entities during a page request.
- *     Defaults to TRUE.
- *   - field cache: (used by Field API loading and saving of field data) FALSE
- *     to disable Field API's persistent cache of field data. Only recommended
- *     if a higher level persistent cache is available for the entity type.
- *     Defaults to TRUE.
- *   - uri callback: A function taking an entity as argument and returning the
- *     URI elements of the entity, e.g. 'path' and 'options'. The actual entity
- *     URI can be constructed by passing these elements to url().
- *   - label callback: (optional) A function taking an entity and optional langcode
- *     argument, and returning the label of the entity. If langcode is omitted, the
- *     entity's default language is used.
- *
- *     The entity label is the main string associated with an entity; for
- *     example, the title of a node or the subject of a comment. If there is an
- *     entity object property that defines the label, use the 'label' element
- *     of the 'entity keys' return value component to provide this information
- *     (see below). If more complex logic is needed to determine the label of
- *     an entity, you can instead specify a callback function here, which will
- *     be called to determine the entity label. See also the
- *     Drupal\Core\Entity\Entity::label() method, which implements this logic.
- *   - fieldable: Set to TRUE if you want your entity type to be fieldable.
- *   - translation: An associative array of modules registered as field
- *     translation handlers. Array keys are the module names, array values
- *     can be any data structure the module uses to provide field translation.
- *     Any empty value disallows the module to appear as a translation handler.
- *   - entity keys: An array describing how the Field API can extract the
- *     information it needs from the objects of the type. Elements:
- *     - id: The name of the property that contains the primary id of the
- *       entity. Every entity object passed to the Field API must have this
- *       property and its value must be numeric.
- *     - revision: The name of the property that contains the revision id of
- *       the entity. The Field API assumes that all revision ids are unique
- *       across all entities of a type. This entry can be omitted if the
- *       entities of this type are not versionable.
- *     - bundle: The name of the property that contains the bundle name for the
- *       entity. The bundle name defines which set of fields are attached to
- *       the entity (e.g. what nodes call "content type"). This entry can be
- *       omitted if this entity type exposes a single bundle (all entities have
- *       the same collection of fields). The name of this single bundle will be
- *       the same as the entity type.
- *     - label: The name of the property that contains the entity label. For
- *       example, if the entity's label is located in $entity->subject, then
- *       'subject' should be specified here. If complex logic is required to
- *       build the label, a 'label callback' should be defined instead (see
- *       the 'label callback' section above for details).
- *     - uuid (optional): The name of the property that contains the universally
- *       unique identifier of the entity, which is used to distinctly identify
- *       an entity across different systems.
- *   - bundle keys: An array describing how the Field API can extract the
- *     information it needs from the bundle objects for this type (e.g
- *     $vocabulary objects for terms; not applicable for nodes). This entry can
- *     be omitted if this type's bundles do not exist as standalone objects.
- *     Elements:
- *     - bundle: The name of the property that contains the name of the bundle
- *       object.
- *   - bundles: An array describing all bundles for this object type. Keys are
- *     bundles machine names, as found in the objects' 'bundle' property
- *     (defined in the 'entity keys' entry above). Elements:
- *     - label: The human-readable name of the bundle.
- *     - uri callback: Same as the 'uri callback' key documented above for the
- *       entity type, but for the bundle only. When determining the URI of an
- *       entity, if a 'uri callback' is defined for both the entity type and
- *       the bundle, the one for the bundle is used.
- *     - admin: An array of information that allows Field UI pages to attach
- *       themselves to the existing administration pages for the bundle.
- *       Elements:
- *       - path: the path of the bundle's main administration page, as defined
- *         in hook_menu(). If the path includes a placeholder for the bundle,
- *         the 'bundle argument', 'bundle helper' and 'real path' keys below
- *         are required.
- *       - bundle argument: The position of the placeholder in 'path', if any.
- *       - real path: The actual path (no placeholder) of the bundle's main
- *         administration page. This will be used to generate links.
- *       - access callback: As in hook_menu(). 'user_access' will be assumed if
- *         no value is provided.
- *       - access arguments: As in hook_menu().
- *   - view modes: An array describing the view modes for the entity type. View
- *     modes let entities be displayed differently depending on the context.
- *     For instance, a node can be displayed differently on its own page
- *     ('full' mode), on the home page or taxonomy listings ('teaser' mode), or
- *     in an RSS feed ('rss' mode). Modules taking part in the display of the
- *     entity (notably the Field API) can adjust their behavior depending on
- *     the requested view mode. An additional 'default' view mode is available
- *     for all entity types. This view mode is not intended for actual entity
- *     display, but holds default display settings. For each available view
- *     mode, administrators can configure whether it should use its own set of
- *     field display settings, or just replicate the settings of the 'default'
- *     view mode, thus reducing the amount of display configurations to keep
- *     track of. Keys of the array are view mode names. Each view mode is
- *     described by an array with the following key/value pairs:
- *     - label: The human-readable name of the view mode
- *     - custom settings: A boolean specifying whether the view mode should by
- *       default use its own custom field display settings. If FALSE, entities
- *       displayed in this view mode will reuse the 'default' display settings
- *       by default (e.g. right after the module exposing the view mode is
- *       enabled), but administrators can later use the Field UI to apply custom
- *       display settings specific to the view mode.
- *
- * @see entity_load()
- * @see entity_load_multiple()
- * @see hook_entity_info_alter()
- */
-function hook_entity_info() {
-  $return = array(
-    'node' => array(
-      'label' => t('Node'),
-      'entity class' => 'Drupal\node\Node',
-      'controller class' => 'Drupal\node\NodeStorageController',
-      'form controller class' => array(
-        'default' => 'Drupal\node\NodeFormController',
-      ),
-      'base table' => 'node',
-      'revision table' => 'node_revision',
-      'uri callback' => 'node_uri',
-      'fieldable' => TRUE,
-      'translation' => array(
-        'locale' => TRUE,
-      ),
-      'entity keys' => array(
-        'id' => 'nid',
-        'revision' => 'vid',
-        'bundle' => 'type',
-        'uuid' => 'uuid',
-      ),
-      'bundle keys' => array(
-        'bundle' => 'type',
-      ),
-      'bundles' => array(),
-      'view modes' => array(
-        'full' => array(
-          'label' => t('Full content'),
-          'custom settings' => FALSE,
-        ),
-        'teaser' => array(
-          'label' => t('Teaser'),
-          'custom settings' => TRUE,
-        ),
-        'rss' => array(
-          'label' => t('RSS'),
-          'custom settings' => FALSE,
-        ),
-      ),
-    ),
-  );
-
-  // Search integration is provided by node.module, so search-related
-  // view modes for nodes are defined here and not in search.module.
-  if (module_exists('search')) {
-    $return['node']['view modes'] += array(
-      'search_index' => array(
-        'label' => t('Search index'),
-        'custom settings' => FALSE,
-      ),
-      'search_result' => array(
-        'label' => t('Search result'),
-        'custom settings' => FALSE,
-      ),
-    );
-  }
-
-  // Bundles must provide a human readable name so we can create help and error
-  // messages, and the path to attach Field admin pages to.
-  foreach (node_type_get_names() as $type => $name) {
-    $return['node']['bundles'][$type] = array(
-      'label' => $name,
-      'admin' => array(
-        'path' => 'admin/structure/types/manage/%node_type',
-        'real path' => 'admin/structure/types/manage/' . $type,
-        'bundle argument' => 4,
-        'access arguments' => array('administer content types'),
-      ),
-    );
-  }
-
-  return $return;
-}
-
-/**
  * Alter the entity info.
  *
  * Modules may implement this hook to alter the information that defines an
- * entity. All properties that are available in hook_entity_info() can be
- * altered here.
+ * entity. All properties that are available in
+ * Drupal\Core\Plugin\Type\EntityManager can be altered here.
+ *
+ * In addition, the following properties should be added here:
+ * - bundles: An array describing all bundles for this object type. Keys are
+ *   bundles machine names, as found in the objects' 'bundle' property
+ *   (defined in the 'entity_keys' entry above). Elements:
+ *   - label: The human-readable name of the bundle.
+ *   - uri_callback: Same as the 'uri_callback' key documented above for the
+ *     entity type, but for the bundle only. When determining the URI of an
+ *     entity, if a 'uri_callback' is defined for both the entity type and
+ *     the bundle, the one for the bundle is used.
+ *   - admin: An array of information that allows Field UI pages to attach
+ *     themselves to the existing administration pages for the bundle.
+ *     Elements:
+ *     - path: the path of the bundle's main administration page, as defined
+ *       in hook_menu(). If the path includes a placeholder for the bundle,
+ *       the 'bundle argument', 'bundle helper' and 'real path' keys below
+ *       are required.
+ *     - bundle argument: The position of the placeholder in 'path', if any.
+ *     - real path: The actual path (no placeholder) of the bundle's main
+ *       administration page. This will be used to generate links.
+ *     - access callback: As in hook_menu(). 'user_access' will be assumed if
+ *       no value is provided.
+ *     - access arguments: As in hook_menu().
+ * - view_modes: An array describing the view modes for the entity type. View
+ *   modes let entities be displayed differently depending on the context.
+ *   For instance, a node can be displayed differently on its own page
+ *   ('full' mode), on the home page or taxonomy listings ('teaser' mode), or
+ *   in an RSS feed ('rss' mode). Modules taking part in the display of the
+ *   entity (notably the Field API) can adjust their behavior depending on
+ *   the requested view mode. An additional 'default' view mode is available
+ *   for all entity types. This view mode is not intended for actual entity
+ *   display, but holds default display settings. For each available view
+ *   mode, administrators can configure whether it should use its own set of
+ *   field display settings, or just replicate the settings of the 'default'
+ *   view mode, thus reducing the amount of display configurations to keep
+ *   track of. Keys of the array are view mode names. Each view mode is
+ *   described by an array with the following key/value pairs:
+ *   - label: The human-readable name of the view mode
+ *   - custom settings: A boolean specifying whether the view mode should by
+ *     default use its own custom field display settings. If FALSE, entities
+ *     displayed in this view mode will reuse the 'default' display settings
+ *     by default (e.g. right after the module exposing the view mode is
+ *     enabled), but administrators can later use the Field UI to apply custom
+ *     display settings specific to the view mode.
  *
  * @param $entity_info
  *   The entity info array, keyed by entity name.
  *
- * @see hook_entity_info()
+ * @see Drupal\Core\Plugin\Type\EntityManager
  */
 function hook_entity_info_alter(&$entity_info) {
   // Set the controller class for nodes to an alternate implementation of the
   // Drupal\Core\Entity\EntityStorageControllerInterface interface.
-  $entity_info['node']['controller class'] = 'Drupal\mymodule\MyCustomNodeStorageController';
+  $entity_info['node']['controller_class'] = 'Drupal\mymodule\MyCustomNodeStorageController';
 }
 
 /**
diff --git a/core/includes/entity.inc b/core/includes/entity.inc
index 48ee728..7bec79b 100644
--- a/core/includes/entity.inc
+++ b/core/includes/entity.inc
@@ -19,7 +19,7 @@
  *   The entity type, e.g. node, for which the info shall be returned, or NULL
  *   to return an array with info about all types.
  *
- * @see hook_entity_info()
+ * @see Drupal\Core\Plugin\Type\EntityManager
  * @see hook_entity_info_alter()
  */
 function entity_get_info($entity_type = NULL) {
@@ -32,8 +32,8 @@ function entity_get_info($entity_type = NULL) {
   }
   $entity_info = &$drupal_static_fast['entity_info'];
 
-  // hook_entity_info() includes translated strings, so each language is cached
-  // separately.
+  // Drupal\Core\Plugin\Type\EntityManager includes translated strings, so each
+  // language is cached separately.
   $langcode = $language_interface->langcode;
 
   if (empty($entity_info)) {
@@ -41,50 +41,7 @@ function entity_get_info($entity_type = NULL) {
       $entity_info = $cache->data;
     }
     else {
-      $entity_info = module_invoke_all('entity_info');
-      // Merge in default values.
-      foreach ($entity_info as $name => $data) {
-        $entity_info[$name] += array(
-          'fieldable' => FALSE,
-          'entity class' => 'Drupal\Core\Entity\Entity',
-          'controller class' => 'Drupal\Core\Entity\DatabaseStorageController',
-          'list controller class' => 'Drupal\Core\Entity\EntityListController',
-          'render controller class' => 'Drupal\Core\Entity\EntityRenderController',
-          'form controller class' => array(
-            'default' => 'Drupal\Core\Entity\EntityFormController',
-          ),
-          'static cache' => TRUE,
-          'field cache' => TRUE,
-          'bundles' => array(),
-          'view modes' => array(),
-          'entity keys' => array(),
-          'translation' => array(),
-        );
-        $entity_info[$name]['entity keys'] += array(
-          'revision' => '',
-          'bundle' => '',
-        );
-        foreach ($entity_info[$name]['view modes'] as $view_mode => $view_mode_info) {
-          $entity_info[$name]['view modes'][$view_mode] += array(
-            'custom settings' => FALSE,
-          );
-        }
-        // If no bundle key is provided, assume a single bundle, named after
-        // the entity type.
-        if (empty($entity_info[$name]['entity keys']['bundle']) && empty($entity_info[$name]['bundles'])) {
-          $entity_info[$name]['bundles'] = array($name => array('label' => $entity_info[$name]['label']));
-        }
-        // Prepare entity schema fields SQL info for
-        // Drupal\Core\Entity\DatabaseStorageControllerInterface::buildQuery().
-        if (isset($entity_info[$name]['base table'])) {
-          $entity_info[$name]['schema_fields_sql']['base table'] = drupal_schema_fields_sql($entity_info[$name]['base table']);
-          if (isset($entity_info[$name]['revision table'])) {
-            $entity_info[$name]['schema_fields_sql']['revision table'] = drupal_schema_fields_sql($entity_info[$name]['revision table']);
-          }
-        }
-      }
-      // Let other modules alter the entity info.
-      drupal_alter('entity_info', $entity_info);
+      $entity_info = drupal_container()->get('plugin.manager.entity')->getDefinitions();
       cache()->set("entity_info:$langcode", $entity_info, CacheBackendInterface::CACHE_PERMANENT, array('entity_info' => TRUE));
     }
   }
@@ -119,7 +76,7 @@ function entity_info_cache_clear() {
  * @return Drupal\Core\Entity\EntityInterface
  *   The entity object, or FALSE if there is no entity with the given id.
  *
- * @see hook_entity_info()
+ * @see Drupal\Core\Plugin\Type\EntityManager
  * @see entity_load_multiple()
  * @see Drupal\Core\Entity\EntityStorageControllerInterface
  * @see Drupal\Core\Entity\DatabaseStorageController
@@ -142,7 +99,7 @@ function entity_load($entity_type, $id, $reset = FALSE) {
  *   The entity object, or FALSE if there is no entity with the given revision
  *   id.
  *
- * @see hook_entity_info()
+ * @see Drupal\Core\Plugin\Type\EntityManager
  * @see Drupal\Core\Entity\EntityStorageControllerInterface
  * @see Drupal\Core\Entity\DatabaseStorageController
  */
@@ -180,14 +137,14 @@ function entity_revision_delete($entity_type, $revision_id) {
  * @throws Drupal\Core\Entity\EntityStorageException
  *   Thrown in case the requested entity type does not support UUIDs.
  *
- * @see hook_entity_info()
+ * @see Drupal\Core\Plugin\Type\EntityManager
  */
 function entity_load_by_uuid($entity_type, $uuid, $reset = FALSE) {
   $entity_info = entity_get_info($entity_type);
-  if (empty($entity_info['entity keys']['uuid'])) {
+  if (empty($entity_info['entity_keys']['uuid'])) {
     throw new EntityStorageException("Entity type $entity_type does not support UUIDs.");
   }
-  $uuid_key = $entity_info['entity keys']['uuid'];
+  $uuid_key = $entity_info['entity_keys']['uuid'];
 
   $controller = entity_get_controller($entity_type);
   if ($reset) {
@@ -208,11 +165,12 @@ function entity_load_by_uuid($entity_type, $uuid, $reset = FALSE) {
  * Drupal\Core\Entity\EntityStorageControllerInterface interface. By default,
  * Drupal\Core\Entity\DatabaseStorageController is used. Entity types can
  * specify that a different class should be used by setting the
- * 'controller class' key in hook_entity_info(). These classes can either
- * implement the Drupal\Core\Entity\EntityStorageControllerInterface interface, or,
- * most commonly, extend the Drupal\Core\Entity\DatabaseStorageController
- * class. See node_entity_info() and the NodeStorageController in node.module as
- * an example.
+ * 'controller_class' key in the entity plugin annotation. These classes can
+ * either implement the Drupal\Core\Entity\EntityStorageControllerInterface
+ * interface, or, most commonly, extend the
+ * Drupal\Core\Entity\DatabaseStorageController class.
+ * See Drupal\node\Plugin\Core\Entity\Node and Drupal\node\NodeStorageController
+ * for an example.
  *
  * @param string $entity_type
  *   The entity type to load, e.g. node or user.
@@ -224,7 +182,7 @@ function entity_load_by_uuid($entity_type, $uuid, $reset = FALSE) {
  * @return array
  *   An array of entity objects indexed by their ids.
  *
- * @see hook_entity_info()
+ * @see Drupal\Core\Plugin\Type\EntityManager
  * @see Drupal\Core\Entity\EntityStorageControllerInterface
  * @see Drupal\Core\Entity\DatabaseStorageController
  * @see Drupal\Core\Entity\EntityFieldQuery
@@ -311,7 +269,7 @@ function entity_get_controller($entity_type) {
   $controllers = &drupal_static(__FUNCTION__, array());
   if (!isset($controllers[$entity_type])) {
     $type_info = entity_get_info($entity_type);
-    $class = $type_info['controller class'];
+    $class = $type_info['controller_class'];
     $controllers[$entity_type] = new $class($entity_type);
   }
   return $controllers[$entity_type];
@@ -348,7 +306,7 @@ function entity_page_label(EntityInterface $entity, $langcode = NULL) {
  * used. If a non-existing non-default operation is specified an exception will
  * be thrown.
  *
- * @see hook_entity_info()
+ * @see Drupal\Core\Plugin\Type\EntityManager
  *
  * @param $entity_type
  *   The type of the entity.
@@ -364,11 +322,11 @@ function entity_form_controller($entity_type, $operation = 'default') {
   $info = entity_get_info($entity_type);
 
   // Check whether there is a form controller class for the specified operation.
-  if (!empty($info['form controller class'][$operation])) {
-    $class = $info['form controller class'][$operation];
+  if (!empty($info['form_controller_class'][$operation])) {
+    $class = $info['form_controller_class'][$operation];
   }
   // If no controller is specified default to the base implementation.
-  elseif (empty($info['form controller class']) && $operation == 'default') {
+  elseif (empty($info['form_controller_class']) && $operation == 'default') {
     $class = 'Drupal\Core\Entity\EntityFormController';
   }
   // If a non-existing operation has been specified stop.
@@ -514,12 +472,12 @@ function entity_form_submit_build_entity($entity_type, $entity, $form, &$form_st
  * @return Drupal\Core\Entity\EntityListControllerInterface
  *   An entity list controller.
  *
- * @see hook_entity_info()
+ * @see Drupal\Core\Plugin\Type\EntityManager
  */
 function entity_list_controller($entity_type) {
   $storage = entity_get_controller($entity_type);
   $entity_info = entity_get_info($entity_type);
-  $class = $entity_info['list controller class'];
+  $class = $entity_info['list_controller_class'];
   return new $class($entity_type, $storage);
 }
 
@@ -532,11 +490,11 @@ function entity_list_controller($entity_type) {
  * @return Drupal\Core\Entity\EntityRenderControllerInterface
  *   An entity render controller.
  *
- * @see hook_entity_info()
+ * @see Drupal\Core\Plugin\Type\EntityManager
  */
 function entity_render_controller($entity_type) {
   $info = entity_get_info($entity_type);
-  $class = $info['render controller class'];
+  $class = $info['render_controller_class'];
   return new $class($entity_type);
 }
 
diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php b/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php
index 07849c6..87bb20a 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php
@@ -64,7 +64,7 @@ public function __construct($entityType) {
     $this->entityType = $entityType;
     $this->entityInfo = entity_get_info($entityType);
     $this->hookLoadArguments = array();
-    $this->idKey = $this->entityInfo['entity keys']['id'];
+    $this->idKey = $this->entityInfo['entity_keys']['id'];
   }
 
   /**
@@ -157,8 +157,8 @@ public function loadByProperties(array $values = array()) {
    *   A SelectQuery object for loading the entity.
    */
   protected function buildQuery($ids, $revision_id = FALSE) {
-    $config_class = $this->entityInfo['entity class'];
-    $prefix = $this->entityInfo['config prefix'] . '.';
+    $config_class = $this->entityInfo['class'];
+    $prefix = $this->entityInfo['config_prefix'] . '.';
 
     // Load all of the configuration entities.
     if ($ids === NULL) {
@@ -219,7 +219,7 @@ protected function attachLoad(&$queried_entities, $revision_id = FALSE) {
    * Implements Drupal\Core\Entity\EntityStorageControllerInterface::create().
    */
   public function create(array $values) {
-    $class = isset($this->entityInfo['entity class']) ? $this->entityInfo['entity class'] : 'Drupal\Core\Entity\Entity';
+    $class = $this->entityInfo['class'];
 
     $entity = new $class($values, $this->entityType);
 
@@ -248,7 +248,7 @@ public function delete($ids) {
     }
 
     foreach ($entities as $id => $entity) {
-      $config = config($this->entityInfo['config prefix'] . '.' . $entity->id());
+      $config = config($this->entityInfo['config_prefix'] . '.' . $entity->id());
       $config->delete();
     }
 
@@ -262,7 +262,7 @@ public function delete($ids) {
    * Implements Drupal\Core\Entity\EntityStorageControllerInterface::save().
    */
   public function save(EntityInterface $entity) {
-    $prefix = $this->entityInfo['config prefix'] . '.';
+    $prefix = $this->entityInfo['config_prefix'] . '.';
 
     // Load the stored entity, if any.
     if ($entity->getOriginalID()) {
diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php
index f1e43d6..2ad563b 100644
--- a/core/lib/Drupal/Core/CoreBundle.php
+++ b/core/lib/Drupal/Core/CoreBundle.php
@@ -66,6 +66,8 @@ public function build(ContainerBuilder $container) {
     $container->register('router.builder', 'Drupal\Core\Routing\RouteBuilder')
       ->addArgument(new Reference('router.dumper'));
 
+    $container->register('plugin.manager.entity', 'Drupal\Core\Plugin\Type\EntityManager');
+
     // @todo Replace below lines with the commented out block below it when it's
     //   performant to do so: http://drupal.org/node/1706064.
     $dispatcher = $container->get('dispatcher');
diff --git a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php b/core/lib/Drupal/Core/Entity/DatabaseStorageController.php
index 6342502..968c284 100644
--- a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php
+++ b/core/lib/Drupal/Core/Entity/DatabaseStorageController.php
@@ -114,27 +114,27 @@ public function __construct($entityType) {
     $this->entityInfo = entity_get_info($entityType);
     $this->entityCache = array();
     $this->hookLoadArguments = array();
-    $this->idKey = $this->entityInfo['entity keys']['id'];
+    $this->idKey = $this->entityInfo['entity_keys']['id'];
 
     // Check if the entity type supports UUIDs.
-    if (!empty($this->entityInfo['entity keys']['uuid'])) {
-      $this->uuidKey = $this->entityInfo['entity keys']['uuid'];
+    if (!empty($this->entityInfo['entity_keys']['uuid'])) {
+      $this->uuidKey = $this->entityInfo['entity_keys']['uuid'];
     }
     else {
       $this->uuidKey = FALSE;
     }
 
     // Check if the entity type supports revisions.
-    if (!empty($this->entityInfo['entity keys']['revision'])) {
-      $this->revisionKey = $this->entityInfo['entity keys']['revision'];
-      $this->revisionTable = $this->entityInfo['revision table'];
+    if (!empty($this->entityInfo['entity_keys']['revision'])) {
+      $this->revisionKey = $this->entityInfo['entity_keys']['revision'];
+      $this->revisionTable = $this->entityInfo['revision_table'];
     }
     else {
       $this->revisionKey = FALSE;
     }
 
     // Check if the entity type supports static caching of loaded entities.
-    $this->cache = !empty($this->entityInfo['static cache']);
+    $this->cache = !empty($this->entityInfo['static_cache']);
   }
 
   /**
@@ -180,11 +180,11 @@ public function load(array $ids = NULL) {
       // Build and execute the query.
       $query_result = $this->buildQuery($ids)->execute();
 
-      if (!empty($this->entityInfo['entity class'])) {
+      if (!empty($this->entityInfo['class'])) {
         // We provide the necessary arguments for PDO to create objects of the
         // specified entity class.
         // @see Drupal\Core\Entity\EntityInterface::__construct()
-        $query_result->setFetchMode(PDO::FETCH_CLASS, $this->entityInfo['entity class'], array(array(), $this->entityType));
+        $query_result->setFetchMode(PDO::FETCH_CLASS, $this->entityInfo['class'], array(array(), $this->entityType));
       }
       $queried_entities = $query_result->fetchAllAssoc($this->idKey);
     }
@@ -225,11 +225,11 @@ public function loadRevision($revision_id) {
     // Build and execute the query.
     $query_result = $this->buildQuery(array(), $revision_id)->execute();
 
-    if (!empty($this->entityInfo['entity class'])) {
+    if (!empty($this->entityInfo['class'])) {
       // We provide the necessary arguments for PDO to create objects of the
       // specified entity class.
       // @see Drupal\Core\Entity\EntityInterface::__construct()
-      $query_result->setFetchMode(PDO::FETCH_CLASS, $this->entityInfo['entity class'], array(array(), $this->entityType));
+      $query_result->setFetchMode(PDO::FETCH_CLASS, $this->entityInfo['class'], array(array(), $this->entityType));
     }
     $queried_entities = $query_result->fetchAllAssoc($this->idKey);
 
@@ -313,7 +313,7 @@ protected function buildPropertyQuery(EntityFieldQuery $entity_query, array $val
    *   A SelectQuery object for loading the entity.
    */
   protected function buildQuery($ids, $revision_id = FALSE) {
-    $query = db_select($this->entityInfo['base table'], 'base');
+    $query = db_select($this->entityInfo['base_table'], 'base');
 
     $query->addTag($this->entityType . '_load_multiple');
 
@@ -325,11 +325,11 @@ protected function buildQuery($ids, $revision_id = FALSE) {
     }
 
     // Add fields from the {entity} table.
-    $entity_fields = $this->entityInfo['schema_fields_sql']['base table'];
+    $entity_fields = $this->entityInfo['schema_fields_sql']['base_table'];
 
     if ($this->revisionKey) {
       // Add all fields from the {entity_revision} table.
-      $entity_revision_fields = drupal_map_assoc($this->entityInfo['schema_fields_sql']['revision table']);
+      $entity_revision_fields = drupal_map_assoc($this->entityInfo['schema_fields_sql']['revision_table']);
       // The id field is provided by entity, so remove it.
       unset($entity_revision_fields[$this->idKey]);
 
@@ -429,7 +429,7 @@ protected function cacheSet($entities) {
    * Implements Drupal\Core\Entity\EntityStorageControllerInterface::create().
    */
   public function create(array $values) {
-    $class = isset($this->entityInfo['entity class']) ? $this->entityInfo['entity class'] : 'Drupal\Core\Entity\Entity';
+    $class = $this->entityInfo['class'];
 
     $entity = new $class($values, $this->entityType);
 
@@ -460,7 +460,7 @@ public function delete($ids) {
       }
       $ids = array_keys($entities);
 
-      db_delete($this->entityInfo['base table'])
+      db_delete($this->entityInfo['base_table'])
         ->condition($this->idKey, $ids, 'IN')
         ->execute();
 
@@ -503,7 +503,7 @@ public function save(EntityInterface $entity) {
 
       if (!$entity->isNew()) {
         if ($entity->isDefaultRevision()) {
-          $return = drupal_write_record($this->entityInfo['base table'], $entity, $this->idKey);
+          $return = drupal_write_record($this->entityInfo['base_table'], $entity, $this->idKey);
         }
         else {
           // @todo, should a different value be returned when saving an entity
@@ -518,7 +518,7 @@ public function save(EntityInterface $entity) {
         $this->invokeHook('update', $entity);
       }
       else {
-        $return = drupal_write_record($this->entityInfo['base table'], $entity);
+        $return = drupal_write_record($this->entityInfo['base_table'], $entity);
         if ($this->revisionKey) {
           $this->saveRevision($entity);
         }
@@ -566,7 +566,7 @@ protected function saveRevision(EntityInterface $entity) {
     if ($entity->isNewRevision()) {
       drupal_write_record($this->revisionTable, $record);
       if ($entity->isDefaultRevision()) {
-        db_update($this->entityInfo['base table'])
+        db_update($this->entityInfo['base_table'])
           ->fields(array($this->revisionKey => $record[$this->revisionKey]))
           ->condition($this->idKey, $entity->id())
           ->execute();
diff --git a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php b/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php
index 007d6d3..6f22d83 100644
--- a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php
+++ b/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php
@@ -41,14 +41,14 @@ class DatabaseStorageControllerNG extends DatabaseStorageController {
    */
   public function __construct($entityType) {
     parent::__construct($entityType);
-    $this->bundleKey = !empty($this->entityInfo['entity keys']['bundle']) ? $this->entityInfo['entity keys']['bundle'] : FALSE;
-    $this->entityClass = $this->entityInfo['entity class'];
+    $this->bundleKey = !empty($this->entityInfo['entity_keys']['bundle']) ? $this->entityInfo['entity_keys']['bundle'] : FALSE;
+    $this->entityClass = $this->entityInfo['class'];
 
     // Work-a-round to let load() get stdClass storage records without having to
     // override it. We map storage records to entities in
     // DatabaseStorageControllerNG:: mapFromStorageRecords().
     // @todo: Remove this once this is moved in the main controller.
-    unset($this->entityInfo['entity class']);
+    unset($this->entityInfo['class']);
   }
 
   /**
@@ -181,13 +181,13 @@ public function save(EntityInterface $entity) {
       $entity->updateOriginalValues();
 
       if (!$entity->isNew()) {
-        $return = drupal_write_record($this->entityInfo['base table'], $record, $this->idKey);
+        $return = drupal_write_record($this->entityInfo['base_table'], $record, $this->idKey);
         $this->resetCache(array($entity->id()));
         $this->postSave($entity, TRUE);
         $this->invokeHook('update', $entity);
       }
       else {
-        $return = drupal_write_record($this->entityInfo['base table'], $record);
+        $return = drupal_write_record($this->entityInfo['base_table'], $record);
         // Reset general caches, but keep caches specific to certain entities.
         $this->resetCache(array());
 
@@ -234,7 +234,7 @@ protected function invokeHook($hook, EntityInterface $entity) {
    */
   protected function mapToStorageRecord(EntityInterface $entity) {
     $record = new \stdClass();
-    foreach ($this->entityInfo['schema_fields_sql']['base table'] as $name) {
+    foreach ($this->entityInfo['schema_fields_sql']['base_table'] as $name) {
       $record->$name = $entity->$name->value;
     }
     return $record;
diff --git a/core/lib/Drupal/Core/Entity/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php
index 8f462de..1d56590 100644
--- a/core/lib/Drupal/Core/Entity/Entity.php
+++ b/core/lib/Drupal/Core/Entity/Entity.php
@@ -99,7 +99,7 @@ public function isNew() {
    */
   public function isNewRevision() {
     $info = $this->entityInfo();
-    return $this->newRevision || (!empty($info['entity keys']['revision']) && !$this->getRevisionId());
+    return $this->newRevision || (!empty($info['entity_keys']['revision']) && !$this->getRevisionId());
   }
 
   /**
@@ -136,11 +136,11 @@ public function bundle() {
   public function label($langcode = NULL) {
     $label = NULL;
     $entity_info = $this->entityInfo();
-    if (isset($entity_info['label callback']) && function_exists($entity_info['label callback'])) {
-      $label = $entity_info['label callback']($this->entityType, $this, $langcode);
+    if (isset($entity_info['label_callback']) && function_exists($entity_info['label_callback'])) {
+      $label = $entity_info['label_callback']($this->entityType, $this, $langcode);
     }
-    elseif (!empty($entity_info['entity keys']['label']) && isset($this->{$entity_info['entity keys']['label']})) {
-      $label = $this->{$entity_info['entity keys']['label']};
+    elseif (!empty($entity_info['entity_keys']['label']) && isset($this->{$entity_info['entity_keys']['label']})) {
+      $label = $this->{$entity_info['entity_keys']['label']};
     }
     return $label;
   }
@@ -153,11 +153,11 @@ public function uri() {
     // A bundle-specific callback takes precedence over the generic one for the
     // entity type.
     $entity_info = $this->entityInfo();
-    if (isset($entity_info['bundles'][$bundle]['uri callback'])) {
-      $uri_callback = $entity_info['bundles'][$bundle]['uri callback'];
+    if (isset($entity_info['bundles'][$bundle]['uri_callback'])) {
+      $uri_callback = $entity_info['bundles'][$bundle]['uri_callback'];
     }
-    elseif (isset($entity_info['uri callback'])) {
-      $uri_callback = $entity_info['uri callback'];
+    elseif (isset($entity_info['uri_callback'])) {
+      $uri_callback = $entity_info['uri_callback'];
     }
     else {
       return NULL;
@@ -330,12 +330,12 @@ public function delete() {
   public function createDuplicate() {
     $duplicate = clone $this;
     $entity_info = $this->entityInfo();
-    $duplicate->{$entity_info['entity keys']['id']} = NULL;
+    $duplicate->{$entity_info['entity_keys']['id']} = NULL;
 
     // Check if the entity type supports UUIDs and generate a new one if so.
-    if (!empty($entity_info['entity keys']['uuid'])) {
+    if (!empty($entity_info['entity_keys']['uuid'])) {
       $uuid = new Uuid();
-      $duplicate->{$entity_info['entity keys']['uuid']} = $uuid->generate();
+      $duplicate->{$entity_info['entity_keys']['uuid']} = $uuid->generate();
     }
     return $duplicate;
   }
diff --git a/core/lib/Drupal/Core/Entity/EntityFieldQuery.php b/core/lib/Drupal/Core/Entity/EntityFieldQuery.php
index 0c054ce..2bf73bd 100644
--- a/core/lib/Drupal/Core/Entity/EntityFieldQuery.php
+++ b/core/lib/Drupal/Core/Entity/EntityFieldQuery.php
@@ -888,14 +888,14 @@ protected function propertyQuery() {
 
     $entity_type = $this->entityConditions['entity_type']['value'];
     $entity_info = entity_get_info($entity_type);
-    if (empty($entity_info['base table'])) {
+    if (empty($entity_info['base_table'])) {
       throw new EntityFieldQueryException(t('Entity %entity has no base table.', array('%entity' => $entity_type)));
     }
 
-    $base_table = $entity_info['base table'];
+    $base_table = $entity_info['base_table'];
     $select_query = db_select($base_table);
     $select_query->addExpression(':entity_type', 'entity_type', array(':entity_type' => $entity_type));
-    $sql_field = $entity_info['entity keys']['id'];
+    $sql_field = $entity_info['entity_keys']['id'];
 
     // If a data table is defined we need to join it and make sure that only one
     // record per entity is returned.
@@ -913,8 +913,8 @@ protected function propertyQuery() {
     }
 
     // If there is a revision key defined, use it.
-    if (!empty($entity_info['entity keys']['revision'])) {
-      $sql_field = $entity_info['entity keys']['revision'];
+    if (!empty($entity_info['entity_keys']['revision'])) {
+      $sql_field = $entity_info['entity_keys']['revision'];
       $select_query->addField($base_table, $sql_field, 'revision_id');
       if (isset($this->entityConditions['revision_id'])) {
         $this->addCondition($select_query, "$base_table.$sql_field", $this->entityConditions['revision_id']);
@@ -927,9 +927,9 @@ protected function propertyQuery() {
     $id_map['revision_id'] = $sql_field;
 
     // Handle bundles.
-    if (!empty($entity_info['entity keys']['bundle'])) {
+    if (!empty($entity_info['entity_keys']['bundle'])) {
       $base_table_schema = drupal_get_schema($base_table);
-      $sql_field = $entity_info['entity keys']['bundle'];
+      $sql_field = $entity_info['entity_keys']['bundle'];
       $having = FALSE;
       if (!empty($base_table_schema['fields'][$sql_field])) {
         $select_query->addField($base_table, $sql_field, 'bundle');
@@ -944,7 +944,7 @@ protected function propertyQuery() {
     $id_map['bundle'] = $sql_field;
 
     if (isset($this->entityConditions['bundle'])) {
-      if (!empty($entity_info['entity keys']['bundle'])) {
+      if (!empty($entity_info['entity_keys']['bundle'])) {
         $this->addCondition($select_query, "$base_table.$sql_field", $this->entityConditions['bundle'], $having);
       }
       else {
@@ -955,7 +955,7 @@ protected function propertyQuery() {
 
     foreach (array('uuid', 'langcode') as $key) {
       if (isset($this->entityConditions[$key])) {
-        $sql_field = !empty($entity_info['entity keys'][$key]) ? $entity_info['entity keys'][$key] : $key;
+        $sql_field = !empty($entity_info['entity_keys'][$key]) ? $entity_info['entity_keys'][$key] : $key;
         if (isset($base_table_schema[$sql_field])) {
           $this->addCondition($select_query, "$base_table.$sql_field", $this->entityConditions[$key]);
         }
@@ -1075,7 +1075,7 @@ public function addCondition(Select $select_query, $sql_field, $condition, $havi
    */
   public function addPropertyConditions(Select $select_query, $entity_type) {
     $entity_info = entity_get_info($entity_type);
-    $entity_base_table = $entity_info['base table'];
+    $entity_base_table = $entity_info['base_table'];
     list($data_table, $data_table_schema) = $this->getPropertyDataSchema($entity_type);
 
     foreach ($this->propertyConditions as $property_condition) {
@@ -1104,7 +1104,7 @@ public function addPropertyOrderBy(Select $select_query, $entity_type, array $or
     $entity_info = entity_get_info($entity_type);
     list($data_table, $data_table_schema) = $this->getPropertyDataSchema($entity_type);
     $specifier = $order['specifier'];
-    $table = !empty($data_table_schema['fields'][$specifier]) ? $data_table  . '_' . $order['langcode_group'] : $entity_info['base table'];
+    $table = !empty($data_table_schema['fields'][$specifier]) ? $data_table  . '_' . $order['langcode_group'] : $entity_info['base_table'];
     $select_query->orderBy("$table.$specifier", $order['direction']);
   }
 
@@ -1126,7 +1126,7 @@ public function joinPropertyData(Select $select_query, $entity_type, $base_table
     // If we have no data table there are no property meta conditions to handle.
     if (!empty($data_table)) {
       $entity_info = entity_get_info($entity_type);
-      $id_key = $entity_info['entity keys']['id'];
+      $id_key = $entity_info['entity_keys']['id'];
       $base_id_key = !empty($base_id_key) ? $base_id_key : $id_key;
 
       foreach ($this->properties as $key => $property) {
@@ -1154,8 +1154,8 @@ public function joinPropertyData(Select $select_query, $entity_type, $base_table
   protected function getPropertyDataSchema($entity_type) {
     $entity_info = entity_get_info($entity_type);
 
-    if (!empty($entity_info['data table'])) {
-      $data_table = $entity_info['data table'];
+    if (!empty($entity_info['data_table'])) {
+      $data_table = $entity_info['data_table'];
       $data_table_schema = drupal_get_schema($data_table);
     }
     else {
diff --git a/core/lib/Drupal/Core/Entity/EntityNG.php b/core/lib/Drupal/Core/Entity/EntityNG.php
index 7520466..2fc7764 100644
--- a/core/lib/Drupal/Core/Entity/EntityNG.php
+++ b/core/lib/Drupal/Core/Entity/EntityNG.php
@@ -398,12 +398,12 @@ public function __unset($name) {
   public function createDuplicate() {
     $duplicate = clone $this;
     $entity_info = $this->entityInfo();
-    $duplicate->{$entity_info['entity keys']['id']}->value = NULL;
+    $duplicate->{$entity_info['entity_keys']['id']}->value = NULL;
 
     // Check if the entity type supports UUIDs and generate a new one if so.
-    if (!empty($entity_info['entity keys']['uuid'])) {
+    if (!empty($entity_info['entity_keys']['uuid'])) {
       $uuid = new Uuid();
-      $duplicate->{$entity_info['entity keys']['uuid']}->value = $uuid->generate();
+      $duplicate->{$entity_info['entity_keys']['uuid']}->value = $uuid->generate();
     }
     return $duplicate;
   }
diff --git a/core/lib/Drupal/Core/Entity/EntityStorageControllerInterface.php b/core/lib/Drupal/Core/Entity/EntityStorageControllerInterface.php
index 153cd80..b36a544 100644
--- a/core/lib/Drupal/Core/Entity/EntityStorageControllerInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityStorageControllerInterface.php
@@ -10,9 +10,9 @@
 /**
  * Defines a common interface for entity controller classes.
  *
- * All entity controller classes specified via the 'controller class' key
- * returned by hook_entity_info() or hook_entity_info_alter() have to implement
- * this interface.
+ * All entity controller classes specified via the 'controller_class' key
+ * returned by Drupal\Core\Plugin\Type\EntityManager or hook_entity_info_alter()
+ * have to implement this interface.
  *
  * Most simple, SQL-based entity controllers will do better by extending
  * Drupal\Core\Entity\DatabaseStorageController instead of implementing this
diff --git a/core/lib/Drupal/Core/Plugin/Discovery/ModuleDecorator.php b/core/lib/Drupal/Core/Plugin/Discovery/ModuleDecorator.php
new file mode 100644
index 0000000..8b7f475
--- /dev/null
+++ b/core/lib/Drupal/Core/Plugin/Discovery/ModuleDecorator.php
@@ -0,0 +1,68 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Plugin\Discovery\ModuleDecorator.
+*/
+
+namespace Drupal\Core\Plugin\Discovery;
+
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+
+/**
+ * Prevents plugins from disabled modules from being loaded.
+ */
+class ModuleDecorator implements DiscoveryInterface {
+
+  /**
+   * The Discovery object being decorated.
+   *
+   * @var Drupal\Component\Plugin\Discovery\DiscoveryInterface
+   */
+  protected $decorated;
+
+  /**
+   * Constructs a Drupal\Core\Plugin\Discovery\ModuleDecorator object.
+   *
+   * It uses the DiscoveryInterface object it should decorate.
+   *
+   * @param Drupal\Component\Plugin\Discovery\DiscoveryInterface $decorated
+   *   The object implementing DiscoveryInterface that is being decorated.
+   */
+  public function __construct(DiscoveryInterface $decorated) {
+    $this->decorated = $decorated;
+  }
+
+  /**
+   * 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().
+   *
+   * Loop through each definition, look for a 'module' key, and check it with
+   * module_exists().
+   */
+  public function getDefinitions() {
+    $definitions = array();
+    foreach ($this->decorated->getDefinitions() as $plugin_id => $definition) {
+      if (isset($definition['module']) && module_exists($definition['module'])) {
+        $definitions[$plugin_id] = $definition;
+      }
+    }
+    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/lib/Drupal/Core/Plugin/Type/EntityManager.php b/core/lib/Drupal/Core/Plugin/Type/EntityManager.php
new file mode 100644
index 0000000..2dd2ad7
--- /dev/null
+++ b/core/lib/Drupal/Core/Plugin/Type/EntityManager.php
@@ -0,0 +1,163 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Plugin\Type\EntityManager.
+ */
+
+namespace Drupal\Core\Plugin\Type;
+
+use Drupal\Component\Plugin\PluginManagerBase;
+use Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator;
+use Drupal\Component\Plugin\Factory\DefaultFactory;
+use Drupal\Core\Plugin\Discovery\AlterDecorator;
+use Drupal\Core\Plugin\Discovery\ModuleDecorator;
+use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
+
+/**
+ * Inform the base system and the Field API about one or more entity types.
+ *
+ * Inform the system about one or more entity types (i.e., object types that
+ * can be loaded via entity_load() and, optionally, to which fields can be
+ * attached).
+ *
+ * @return
+ *   An array whose keys are entity type names and whose values identify
+ *   properties of those types that the system needs to know about:
+ *   - label: The human-readable name of the type.
+ *   - module: The name of the module providing the type.
+ *   - controller_class: The name of the class that is used to load the objects.
+ *     The class has to implement the
+ *     Drupal\Core\Entity\EntityStorageControllerInterface interface. Leave blank
+ *     to use the Drupal\Core\Entity\DatabaseStorageController implementation.
+ *   - render_controller_class: The name of the class that is used to render
+ *     the entities. Deafaults to Drupal\Core\Entity\EntityRenderController.
+ *   - form_controller_class: An associative array where the keys are the names
+ *     of the different form operations (such as creation, editing or deletion)
+ *     and the values are the names of the controller classes. To facilitate
+ *     supporting the case where an entity form varies only slightly between
+ *     different operations, the name of the operation is passed also to the
+ *     constructor of the form controller class. This way, one class can be used
+ *     for multiple entity forms.
+ *   - list_controller_class: The name of the class that is used to provide
+ *     listings of the entity. The class must implement
+ *     Drupal\Core\Entity\EntityListControllerInterface. Defaults to
+ *     Drupal\Core\Entity\EntityListController.
+ *   - base_table: (used by Drupal\Core\Entity\DatabaseStorageController) The
+ *     name of the entity type's base table.
+ *   - static_cache: (used by Drupal\Core\Entity\DatabaseStorageController)
+ *     FALSE to disable static caching of entities during a page request.
+ *     Defaults to TRUE.
+ *   - field_cache: (used by Field API loading and saving of field data) FALSE
+ *     to disable Field API's persistent cache of field data. Only recommended
+ *     if a higher level persistent cache is available for the entity type.
+ *     Defaults to TRUE.
+ *   - uri_callback: A function taking an entity as argument and returning the
+ *     URI elements of the entity, e.g. 'path' and 'options'. The actual entity
+ *     URI can be constructed by passing these elements to url().
+ *   - label_callback: (optional) A function taking an entity and optional
+ *     langcode argument, and returning the label of the entity. If langcode is
+ *     omitted, the entity's default language is used.
+ *     The entity label is the main string associated with an entity; for
+ *     example, the title of a node or the subject of a comment. If there is an
+ *     entity object property that defines the label, use the 'label' element
+ *     of the 'entity_keys' return value component to provide this information
+ *     (see below). If more complex logic is needed to determine the label of
+ *     an entity, you can instead specify a callback function here, which will
+ *     be called to determine the entity label. See also the
+ *     Drupal\Core\Entity\Entity::label() method, which implements this logic.
+ *   - fieldable: Set to TRUE if you want your entity type to be fieldable.
+ *   - translation: An associative array of modules registered as field
+ *     translation handlers. Array keys are the module names, array values
+ *     can be any data structure the module uses to provide field translation.
+ *     Any empty value disallows the module to appear as a translation handler.
+ *   - entity_keys: An array describing how the Field API can extract the
+ *     information it needs from the objects of the type. Elements:
+ *     - id: The name of the property that contains the primary id of the
+ *       entity. Every entity object passed to the Field API must have this
+ *       property and its value must be numeric.
+ *     - revision: The name of the property that contains the revision id of
+ *       the entity. The Field API assumes that all revision ids are unique
+ *       across all entities of a type. This entry can be omitted if the
+ *       entities of this type are not versionable.
+ *     - bundle: The name of the property that contains the bundle name for the
+ *       entity. The bundle name defines which set of fields are attached to
+ *       the entity (e.g. what nodes call "content type"). This entry can be
+ *       omitted if this entity type exposes a single bundle (all entities have
+ *       the same collection of fields). The name of this single bundle will be
+ *       the same as the entity type.
+ *     - label: The name of the property that contains the entity label. For
+ *       example, if the entity's label is located in $entity->subject, then
+ *       'subject' should be specified here. If complex logic is required to
+ *       build the label, a 'label_callback' should be defined instead (see
+ *       the 'label_callback' section above for details).
+ *     - uuid (optional): The name of the property that contains the universally
+ *       unique identifier of the entity, which is used to distinctly identify
+ *       an entity across different systems.
+ *   - bundle_keys: An array describing how the Field API can extract the
+ *     information it needs from the bundle objects for this type (e.g
+ *     $vocabulary objects for terms; not applicable for nodes). This entry can
+ *     be omitted if this type's bundles do not exist as standalone objects.
+ *     Elements:
+ *     - bundle: The name of the property that contains the name of the bundle
+ *       object.
+ *
+ * @see entity_load()
+ * @see entity_load_multiple()
+ * @see hook_entity_info_alter()
+ */
+class EntityManager extends PluginManagerBase {
+
+  public function __construct() {
+    $this->discovery = new ModuleDecorator(new AlterDecorator(new DerivativeDiscoveryDecorator(new AnnotatedClassDiscovery('Core', 'Entity')), 'entity_info'));
+    $this->factory = new DefaultFactory($this);
+
+    $this->defaults = array(
+      'fieldable' => FALSE,
+      'class' => 'Drupal\Core\Entity\Entity',
+      'controller_class' => 'Drupal\Core\Entity\DatabaseStorageController',
+      'list_controller_class' => 'Drupal\Core\Entity\EntityListController',
+      'render_controller_class' => 'Drupal\Core\Entity\EntityRenderController',
+      'form_controller_class' => array(
+        'default' => 'Drupal\Core\Entity\EntityFormController',
+      ),
+      'static_cache' => TRUE,
+      'field_cache' => TRUE,
+      'bundles' => array(),
+      'view_modes' => array(),
+      'entity_keys' => array(
+        'revision' => '',
+        'bundle' => '',
+      ),
+      'translation' => array(),
+    );
+  }
+
+  /**
+   * Overrides Drupal\Component\Plugin\PluginManagerBase::processDefinition().
+   */
+  protected function processDefinition(&$definition, $plugin_id) {
+    parent::processDefinition($definition, $plugin_id);
+
+    foreach ($definition['view_modes'] as $view_mode => $view_mode_info) {
+      $definition['view_modes'][$view_mode] += array(
+        'custom settings' => FALSE,
+      );
+    }
+
+    // If no bundle key is provided, assume a single bundle, named after
+    // the entity type.
+    if (empty($definition['entity_keys']['bundle']) && empty($definition['bundles'])) {
+      $definition['bundles'] = array($plugin_id => array('label' => $definition['label']));
+    }
+    // Prepare entity schema fields SQL info for
+    // Drupal\Core\Entity\DatabaseStorageControllerInterface::buildQuery().
+    if (isset($definition['base_table'])) {
+      $definition['schema_fields_sql']['base_table'] = drupal_schema_fields_sql($definition['base_table']);
+      if (isset($definition['revision_table'])) {
+        $definition['schema_fields_sql']['revision_table'] = drupal_schema_fields_sql($definition['revision_table']);
+      }
+    }
+  }
+
+}
diff --git a/core/modules/book/book.admin.inc b/core/modules/book/book.admin.inc
index fbd8dda..27f5cae 100644
--- a/core/modules/book/book.admin.inc
+++ b/core/modules/book/book.admin.inc
@@ -5,7 +5,7 @@
  * Admin page callbacks for the book module.
  */
 
-use Drupal\node\Node;
+use Drupal\node\Plugin\Core\Entity\Node;
 
 /**
  * Page callback: Returns an administrative overview of all books.
diff --git a/core/modules/book/book.module b/core/modules/book/book.module
index 7c43e28..c30e66f 100644
--- a/core/modules/book/book.module
+++ b/core/modules/book/book.module
@@ -5,7 +5,7 @@
  * Allows users to create and organize related content in an outline.
  */
 
-use Drupal\node\Node;
+use Drupal\node\Plugin\Core\Entity\Node;
 use Drupal\Core\Template\Attribute;
 
 /**
@@ -253,7 +253,10 @@ function book_admin_paths() {
  */
 function book_entity_info_alter(&$info) {
   // Add the 'Print' view mode for nodes.
-  $info['node']['view modes'] += array(
+  if (!isset($info['node']['view_modes'])) {
+    $info['node']['view_modes'] = array();
+  }
+  $info['node']['view_modes'] += array(
     'print' => array(
       'label' => t('Print'),
       'custom settings' => FALSE,
diff --git a/core/modules/book/book.pages.inc b/core/modules/book/book.pages.inc
index 90b2192..ae79318 100644
--- a/core/modules/book/book.pages.inc
+++ b/core/modules/book/book.pages.inc
@@ -5,7 +5,7 @@
  * User page callbacks for the book module.
  */
 
-use Drupal\node\Node;
+use Drupal\node\Plugin\Core\Entity\Node;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 
diff --git a/core/modules/book/lib/Drupal/book/Tests/BookTest.php b/core/modules/book/lib/Drupal/book/Tests/BookTest.php
index a1a88c4..5f50fe8 100644
--- a/core/modules/book/lib/Drupal/book/Tests/BookTest.php
+++ b/core/modules/book/lib/Drupal/book/Tests/BookTest.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\book\Tests;
 
-use Drupal\node\Node;
+use Drupal\node\Plugin\Core\Entity\Node;
 use Drupal\simpletest\WebTestBase;
 
 class BookTest extends WebTestBase {
diff --git a/core/modules/breakpoint/breakpoint.module b/core/modules/breakpoint/breakpoint.module
index 2b07f22..54f06a2 100644
--- a/core/modules/breakpoint/breakpoint.module
+++ b/core/modules/breakpoint/breakpoint.module
@@ -5,8 +5,8 @@
  * Manage breakpoints and breakpoint groups for responsive designs.
  */
 
-use Drupal\breakpoint\Breakpoint;
-use Drupal\breakpoint\BreakpointGroup;
+use Drupal\breakpoint\Plugin\Core\Entity\Breakpoint;
+use Drupal\breakpoint\Plugin\Core\Entity\BreakpointGroup;
 
 /**
  * Implements hook_help().
@@ -210,7 +210,7 @@ function _breakpoint_delete_breakpoints($list, $source_type) {
 
   // Remove the breakpoint.breakpoint part of the breakpoint identifier.
   foreach ($ids as &$id) {
-    $id = drupal_substr($id, drupal_strlen($entity_info['config prefix']) + 1);
+    $id = drupal_substr($id, drupal_strlen($entity_info['config_prefix']) + 1);
   }
   $breakpoint_groups = entity_load_multiple('breakpoint_group', $ids);
 
@@ -225,7 +225,7 @@ function _breakpoint_delete_breakpoints($list, $source_type) {
 
       // Remove the breakpoint.breakpoint part of the breakpoint identifier.
       foreach ($breakpoint_ids as &$breakpoint_id) {
-        $breakpoint_id = drupal_substr($breakpoint_id, drupal_strlen($entity_info['config prefix']) + 1);
+        $breakpoint_id = drupal_substr($breakpoint_id, drupal_strlen($entity_info['config_prefix']) + 1);
       }
       $breakpoints = entity_load_multiple('breakpoint', $breakpoint_ids);
 
@@ -307,45 +307,12 @@ function breakpoint_get_module_media_queries($module) {
 }
 
 /**
- * Implements hook_entity_info().
- */
-function breakpoint_entity_info() {
-  // Breakpoint.
-  $types['breakpoint'] = array(
-    'label' => 'Breakpoint',
-    'entity class' => 'Drupal\breakpoint\Breakpoint',
-    'controller class' => 'Drupal\Core\Config\Entity\ConfigStorageController',
-    'config prefix' => 'breakpoint.breakpoint',
-    'entity keys' => array(
-      'id' => 'id',
-      'label' => 'label',
-      'uuid' => 'uuid',
-    ),
-  );
-
-  // Breakpoint group.
-  $types['breakpoint_group'] = array(
-    'label' => 'Breakpoint group',
-    'entity class' => 'Drupal\breakpoint\BreakpointGroup',
-    'controller class' => 'Drupal\Core\Config\Entity\ConfigStorageController',
-    'config prefix' => 'breakpoint.breakpoint_group',
-    'entity keys' => array(
-      'id' => 'id',
-      'label' => 'label',
-      'uuid' => 'uuid',
-    ),
-  );
-
-  return $types;
-}
-
-/**
  * Load one breakpoint group by its identifier.
  *
  * @param string $id
  *   The id of the breakpoint group to load.
  *
- * @return Drupal\breakpoint\BreakpointGroup|false
+ * @return Drupal\breakpoint\Plugin\Core\Entity\BreakpointGroup|false
  *   The breakpoint group, or FALSE if there is no entity with the given id.
  *
  * @todo Remove this in a follow-up issue.
@@ -361,7 +328,7 @@ function breakpoint_group_load($id) {
  * @param int $id
  *   The id of the breakpoint to load.
  *
- * @return Drupal\breakpoint\Breakpoint
+ * @return Drupal\breakpoint\Plugin\Core\Entity\Breakpoint
  *   The entity object, or FALSE if there is no entity with the given id.
  *
  * @todo Remove this in a follow-up issue.
@@ -415,7 +382,7 @@ function breakpoint_select_options() {
  * @param string $sourceType
  *   Either Breakpoint::SOURCE_TYPE_THEME or Breakpoint::SOURCE_TYPE_MODULE.
  *
- * @return Drupal\breakpoint\BreakpointGroup
+ * @return Drupal\breakpoint\Plugin\Core\Entity\BreakpointGroup
  *
  * @see _breakpoint_import_media_queries()
  * @see _breakpoint_import_breakpoint_groups()
diff --git a/core/modules/breakpoint/lib/Drupal/breakpoint/Breakpoint.php b/core/modules/breakpoint/lib/Drupal/breakpoint/Plugin/Core/Entity/Breakpoint.php
similarity index 95%
rename from core/modules/breakpoint/lib/Drupal/breakpoint/Breakpoint.php
rename to core/modules/breakpoint/lib/Drupal/breakpoint/Plugin/Core/Entity/Breakpoint.php
index db9caf2..dfe00ee 100644
--- a/core/modules/breakpoint/lib/Drupal/breakpoint/Breakpoint.php
+++ b/core/modules/breakpoint/lib/Drupal/breakpoint/Plugin/Core/Entity/Breakpoint.php
@@ -2,10 +2,10 @@
 
 /**
  * @file
- * Definition of Drupal\breakpoint\Breakpoint.
+ * Definition of Drupal\breakpoint\Plugin\Core\Entity\Breakpoint.
  */
 
-namespace Drupal\breakpoint;
+namespace Drupal\breakpoint\Plugin\Core\Entity;
 
 use Drupal\Core\Config\Entity\ConfigEntityBase;
 use Drupal\breakpoint\InvalidBreakpointException;
@@ -13,9 +13,24 @@
 use Drupal\breakpoint\InvalidBreakpointSourceException;
 use Drupal\breakpoint\InvalidBreakpointSourceTypeException;
 use Drupal\breakpoint\InvalidBreakpointMediaQueryException;
+use Drupal\Core\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
 
 /**
  * Defines the Breakpoint entity.
+ *
+ * @Plugin(
+ *   id = "breakpoint",
+ *   label = @Translation("Breakpoint"),
+ *   module = "breakpoint",
+ *   controller_class = "Drupal\Core\Config\Entity\ConfigStorageController",
+ *   config_prefix = "breakpoint.breakpoint",
+ *   entity_keys = {
+ *     "id" = "id",
+ *     "label" = "label",
+ *     "uuid" = "uuid"
+ *   }
+ * )
  */
 class Breakpoint extends ConfigEntityBase {
 
diff --git a/core/modules/breakpoint/lib/Drupal/breakpoint/BreakpointGroup.php b/core/modules/breakpoint/lib/Drupal/breakpoint/Plugin/Core/Entity/BreakpointGroup.php
similarity index 89%
rename from core/modules/breakpoint/lib/Drupal/breakpoint/BreakpointGroup.php
rename to core/modules/breakpoint/lib/Drupal/breakpoint/Plugin/Core/Entity/BreakpointGroup.php
index b6e6a9f..d3cacf3 100644
--- a/core/modules/breakpoint/lib/Drupal/breakpoint/BreakpointGroup.php
+++ b/core/modules/breakpoint/lib/Drupal/breakpoint/Plugin/Core/Entity/BreakpointGroup.php
@@ -2,17 +2,32 @@
 
 /**
  * @file
- * Definition of Drupal\breakpoint\BreakpointGroup.
+ * Definition of Drupal\breakpoint\Plugin\Core\Entity\BreakpointGroup.
  */
 
-namespace Drupal\breakpoint;
+namespace Drupal\breakpoint\Plugin\Core\Entity;
 
 use Drupal\Core\Config\Entity\ConfigEntityBase;
 use Drupal\breakpoint\InvalidBreakpointSourceException;
 use Drupal\breakpoint\InvalidBreakpointSourceTypeException;
+use Drupal\Core\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
 
 /**
  * Defines the BreakpointGroup entity.
+ *
+ * @Plugin(
+ *   id = "breakpoint_group",
+ *   label = @Translation("Breakpoint group"),
+ *   module = "breakpoint",
+ *   controller_class = "Drupal\Core\Config\Entity\ConfigStorageController",
+ *   config_prefix = "breakpoint.breakpoint_group",
+ *   entity_keys = {
+ *     "id" = "id",
+ *     "label" = "label",
+ *     "uuid" = "uuid"
+ *   }
+ * )
  */
 class BreakpointGroup extends ConfigEntityBase {
 
@@ -50,7 +65,7 @@ class BreakpointGroup extends ConfigEntityBase {
    * @var array
    *   Array containing all breakpoints of this group.
    *
-   * @see Drupal\breakpoints\Breakpoint
+   * @see Drupal\breakpoint\Plugin\Core\Entity\Breakpoint
    */
   public $breakpoints = array();
 
@@ -71,7 +86,7 @@ class BreakpointGroup extends ConfigEntityBase {
    *     Breakpoint::SOURCE_TYPE_MODULE
    *     Breakpoint::SOURCE_TYPE_USER_DEFINED
    *
-   * @see Drupal\breakpoint\Breakpoint
+   * @see Drupal\breakpoint\Plugin\Core\Entity\Breakpoint
    */
   public $sourceType = Breakpoint::SOURCE_TYPE_USER_DEFINED;
 
diff --git a/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointAPITest.php b/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointAPITest.php
index 24c2ae9..f65b559 100644
--- a/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointAPITest.php
+++ b/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointAPITest.php
@@ -7,7 +7,7 @@
 namespace Drupal\breakpoint\Tests;
 
 use Drupal\breakpoint\Tests\BreakpointsTestBase;
-use Drupal\breakpoint\Breakpoint;
+use Drupal\breakpoint\Plugin\Core\Entity\Breakpoint;
 use Drupal\breakpoint\InvalidBreakpointNameException;
 use Drupal\breakpoint\InvalidBreakpointSourceException;
 use Drupal\breakpoint\InvalidBreakpointSourceTypeException;
diff --git a/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointCRUDTest.php b/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointCRUDTest.php
index 1d5d6e1..37caff7 100644
--- a/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointCRUDTest.php
+++ b/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointCRUDTest.php
@@ -7,7 +7,7 @@
 namespace Drupal\breakpoint\Tests;
 
 use Drupal\breakpoint\Tests\BreakpointTestBase;
-use Drupal\breakpoint\Breakpoint;
+use Drupal\breakpoint\Plugin\Core\Entity\Breakpoint;
 
 /**
  * Tests for breakpoint CRUD operations.
diff --git a/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointGroupAPITest.php b/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointGroupAPITest.php
index 9fd2ee3..d2bc016 100644
--- a/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointGroupAPITest.php
+++ b/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointGroupAPITest.php
@@ -7,8 +7,8 @@
 namespace Drupal\breakpoint\Tests;
 
 use Drupal\breakpoint\Tests\BreakpointsTestBase;
-use Drupal\breakpoint\BreakpointGroup;
-use Drupal\breakpoint\Breakpoint;
+use Drupal\breakpoint\Plugin\Core\Entity\BreakpointGroup;
+use Drupal\breakpoint\Plugin\Core\Entity\Breakpoint;
 use Drupal\breakpoint\InvalidBreakpointNameException;
 use Drupal\breakpoint\InvalidBreakpointSourceException;
 use Drupal\breakpoint\InvalidBreakpointSourceTypeException;
diff --git a/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointGroupCRUDTest.php b/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointGroupCRUDTest.php
index 72d6c1e..05eaeaf 100644
--- a/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointGroupCRUDTest.php
+++ b/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointGroupCRUDTest.php
@@ -7,8 +7,8 @@
 namespace Drupal\breakpoint\Tests;
 
 use Drupal\breakpoint\Tests\BreakpointGroupTestBase;
-use Drupal\breakpoint\BreakpointGroup;
-use Drupal\breakpoint\Breakpoint;
+use Drupal\breakpoint\Plugin\Core\Entity\BreakpointGroup;
+use Drupal\breakpoint\Plugin\Core\Entity\Breakpoint;
 
 /**
  * Tests for breakpoint group CRUD operations.
diff --git a/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointGroupTestBase.php b/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointGroupTestBase.php
index febf71d..ee1e57d 100644
--- a/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointGroupTestBase.php
+++ b/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointGroupTestBase.php
@@ -7,7 +7,7 @@
 namespace Drupal\breakpoint\Tests;
 
 use Drupal\simpletest\WebTestBase;
-use Drupal\breakpoint\BreakpointGroup;
+use Drupal\breakpoint\Plugin\Core\Entity\BreakpointGroup;
 
 /**
  * Base class for Breakpoint group tests.
diff --git a/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointMediaQueryTest.php b/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointMediaQueryTest.php
index 1696c2b..d0ee5fb 100644
--- a/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointMediaQueryTest.php
+++ b/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointMediaQueryTest.php
@@ -7,7 +7,7 @@
 namespace Drupal\breakpoint\Tests;
 
 use Drupal\simpletest\UnitTestBase;
-use Drupal\breakpoint\Breakpoint;
+use Drupal\breakpoint\Plugin\Core\Entity\Breakpoint;
 use Drupal\breakpoint\InvalidBreakpointMediaQueryException;
 
 /**
diff --git a/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointTestBase.php b/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointTestBase.php
index f8f2b35..cca4d62 100644
--- a/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointTestBase.php
+++ b/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointTestBase.php
@@ -7,7 +7,7 @@
 namespace Drupal\breakpoint\Tests;
 
 use Drupal\simpletest\WebTestBase;
-use Drupal\breakpoint\Breakpoint;
+use Drupal\breakpoint\Plugin\Core\Entity\Breakpoint;
 
 /**
  * Base class for Breakpoint tests.
diff --git a/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointThemeTest.php b/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointThemeTest.php
index 0737611..0091300 100644
--- a/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointThemeTest.php
+++ b/core/modules/breakpoint/lib/Drupal/breakpoint/Tests/BreakpointThemeTest.php
@@ -7,8 +7,8 @@
 namespace Drupal\breakpoint\Tests;
 
 use Drupal\breakpoint\Tests\BreakpointGroupTestBase;
-use Drupal\breakpoint\BreakpointGroup;
-use Drupal\breakpoint\Breakpoint;
+use Drupal\breakpoint\Plugin\Core\Entity\BreakpointGroup;
+use Drupal\breakpoint\Plugin\Core\Entity\Breakpoint;
 
 /**
  * Test breakpoints provided by themes.
diff --git a/core/modules/comment/comment.admin.inc b/core/modules/comment/comment.admin.inc
index dcbd1bc..26e9c8b 100644
--- a/core/modules/comment/comment.admin.inc
+++ b/core/modules/comment/comment.admin.inc
@@ -5,7 +5,7 @@
  * Admin page callbacks for the Comment module.
  */
 
-use Drupal\comment\Comment;
+use Drupal\comment\Plugin\Core\Entity\Comment;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 
 /**
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index df0a33a..c8360fb 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -9,8 +9,8 @@
  * book page, etc.
  */
 
-use Drupal\node\Node;
-use Drupal\file\File;
+use Drupal\node\Plugin\Core\Entity\Node;
+use Drupal\file\Plugin\Core\Entity\File;
 use Drupal\Core\Entity\EntityInterface;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
@@ -76,7 +76,7 @@
  */
 const COMMENT_NODE_OPEN = 2;
 
-use Drupal\comment\Comment;
+use Drupal\comment\Plugin\Core\Entity\Comment;
 
 /**
  * Implements hook_help().
@@ -98,40 +98,18 @@ function comment_help($path, $arg) {
 }
 
 /**
- * Implements hook_entity_info().
+ * Implements hook_entity_info_alter().
  */
-function comment_entity_info() {
-  $return = array(
-    'comment' => array(
-      'label' => t('Comment'),
-      'base table' => 'comment',
-      'uri callback' => 'comment_uri',
-      'fieldable' => TRUE,
-      'controller class' => 'Drupal\comment\CommentStorageController',
-      'form controller class' => array(
-        'default' => 'Drupal\comment\CommentFormController',
-      ),
-      'entity class' => 'Drupal\comment\Comment',
-      'entity keys' => array(
-        'id' => 'cid',
-        'bundle' => 'node_type',
-        'label' => 'subject',
-        'uuid' => 'uuid',
-      ),
-      'bundles' => array(),
-      'render controller class' => 'Drupal\comment\CommentRenderController',
-      'view modes' => array(
-        'full' => array(
-          'label' => t('Full comment'),
-          'custom settings' => FALSE,
-        ),
-      ),
-      'static cache' => FALSE,
+function comment_entity_info_alter(&$info) {
+  $info['comment']['view_modes'] = array(
+    'full' => array(
+      'label' => t('Full comment'),
+      'custom settings' => FALSE,
     ),
   );
 
   foreach (node_type_get_names() as $type => $name) {
-    $return['comment']['bundles']['comment_node_' . $type] = array(
+    $info['comment']['bundles']['comment_node_' . $type] = array(
       'label' => t('@node_type comment', array('@node_type' => $name)),
       // Provide the node type/bundle name for other modules, so it does not
       // have to be extracted manually from the bundle name.
@@ -150,8 +128,6 @@ function comment_entity_info() {
       ),
     );
   }
-
-  return $return;
 }
 
 /**
diff --git a/core/modules/comment/comment.pages.inc b/core/modules/comment/comment.pages.inc
index 3d1ecb9..6263660 100644
--- a/core/modules/comment/comment.pages.inc
+++ b/core/modules/comment/comment.pages.inc
@@ -5,7 +5,7 @@
  * User page callbacks for the Comment module.
  */
 
-use Drupal\node\Node;
+use Drupal\node\Plugin\Core\Entity\Node;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 
diff --git a/core/modules/comment/lib/Drupal/comment/Comment.php b/core/modules/comment/lib/Drupal/comment/Plugin/Core/Entity/Comment.php
similarity index 67%
rename from core/modules/comment/lib/Drupal/comment/Comment.php
rename to core/modules/comment/lib/Drupal/comment/Plugin/Core/Entity/Comment.php
index ef6c16a..c2dd9f2 100644
--- a/core/modules/comment/lib/Drupal/comment/Comment.php
+++ b/core/modules/comment/lib/Drupal/comment/Plugin/Core/Entity/Comment.php
@@ -2,16 +2,39 @@
 
 /**
  * @file
- * Definition of Drupal\comment\Comment.
+ * Definition of Drupal\comment\Plugin\Core\Entity\Comment.
  */
 
-namespace Drupal\comment;
+namespace Drupal\comment\Plugin\Core\Entity;
 
 use Drupal\Core\Entity\ContentEntityInterface;
 use Drupal\Core\Entity\Entity;
+use Drupal\Core\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
 
 /**
  * Defines the comment entity class.
+ *
+ * @Plugin(
+ *   id = "comment",
+ *   label = @Translation("Comment"),
+ *   module = "comment",
+ *   controller_class = "Drupal\comment\CommentStorageController",
+ *   render_controller_class = "Drupal\comment\CommentRenderController",
+ *   form_controller_class = {
+ *     "default" = "Drupal\comment\CommentFormController"
+ *   },
+ *   base_table = "comment",
+ *   uri_callback = "comment_uri",
+ *   fieldable = TRUE,
+ *   static_cache = FALSE,
+ *   entity_keys = {
+ *     "id" = "cid",
+ *     "bundle" = "node_type",
+ *     "label" = "subject",
+ *     "uuid" = "uuid"
+ *   }
+ * )
  */
 class Comment extends Entity implements ContentEntityInterface {
 
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php
index 37a8b47..e8bab5d 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\comment\Tests;
 
-use Drupal\comment\Comment;
+use Drupal\comment\Plugin\Core\Entity\Comment;
 use Drupal\simpletest\WebTestBase;
 
 /**
diff --git a/core/modules/config/config.api.php b/core/modules/config/config.api.php
index 147412d..d845667 100644
--- a/core/modules/config/config.api.php
+++ b/core/modules/config/config.api.php
@@ -69,7 +69,7 @@ function hook_config_import_change($name, $new_config, $old_config) {
   // @todo Make this less ugly.
   list($entity_type) = explode('.', $name);
   $entity_info = entity_get_info($entity_type);
-  $id = substr($name, strlen($entity_info['config prefix']) + 1);
+  $id = substr($name, strlen($entity_info['config_prefix']) + 1);
   $config_test = entity_load('config_test', $id);
 
   // Store the original config, and iterate through each property to store it.
@@ -119,7 +119,7 @@ function hook_config_import_delete($name, $new_config, $old_config) {
   //   config objects as a standard?
   list($entity_type) = explode('.', $name);
   $entity_info = entity_get_info($entity_type);
-  $id = substr($name, strlen($entity_info['config prefix']) + 1);
+  $id = substr($name, strlen($entity_info['config_prefix']) + 1);
   config_test_delete($id);
   return TRUE;
 }
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigEntityListTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigEntityListTest.php
index cd48f71..80698c1 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigEntityListTest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigEntityListTest.php
@@ -8,7 +8,7 @@
 namespace Drupal\config\Tests;
 
 use Drupal\simpletest\WebTestBase;
-use Drupal\config_test\ConfigTest;
+use Drupal\config_test\Plugin\Core\Entity\ConfigTest;
 use Drupal\Core\Entity\EntityStorageControllerInterface;
 
 /**
diff --git a/core/modules/config/tests/config_test/config_test.module b/core/modules/config/tests/config_test/config_test.module
index 44df4da..180bec1 100644
--- a/core/modules/config/tests/config_test/config_test.module
+++ b/core/modules/config/tests/config_test/config_test.module
@@ -5,7 +5,7 @@
  * Provides Config module hook implementations for testing purposes.
  */
 
-use Drupal\config_test\ConfigTest;
+use Drupal\config_test\Plugin\Core\Entity\ConfigTest;
 
 require_once dirname(__FILE__) . '/config_test.hooks.inc';
 
@@ -37,7 +37,7 @@ function config_test_config_import_change($name, $new_config, $old_config) {
   // @todo Make this less ugly.
   list($entity_type) = explode('.', $name);
   $entity_info = entity_get_info($entity_type);
-  $id = substr($name, strlen($entity_info['config prefix']) + 1);
+  $id = substr($name, strlen($entity_info['config_prefix']) + 1);
   $config_test = entity_load('config_test', $id);
 
   // Store the original config, and iterate through each property to store it.
@@ -69,35 +69,15 @@ function config_test_config_import_delete($name, $new_config, $old_config) {
   // @todo Make this less ugly.
   list($entity_type) = explode('.', $name);
   $entity_info = entity_get_info($entity_type);
-  $id = substr($name, strlen($entity_info['config prefix']) + 1);
+  $id = substr($name, strlen($entity_info['config_prefix']) + 1);
   config_test_delete($id);
   return TRUE;
 }
 
 /**
- * Implements hook_entity_info().
- */
-function config_test_entity_info() {
-  $types['config_test'] = array(
-    'label' => 'Test configuration',
-    'controller class' => 'Drupal\Core\Config\Entity\ConfigStorageController',
-    'entity class' => 'Drupal\config_test\ConfigTest',
-    'list controller class' => 'Drupal\Core\Config\Entity\ConfigEntityListController',
-    'uri callback' => 'config_test_uri',
-    'config prefix' => 'config_test.dynamic',
-    'entity keys' => array(
-      'id' => 'id',
-      'label' => 'label',
-      'uuid' => 'uuid',
-    ),
-  );
-  return $types;
-}
-
-/**
  * Entity URI callback.
  *
- * @param Drupal\config_test\ConfigTest $config_test
+ * @param Drupal\config_test\Plugin\Core\Entity\ConfigTest $config_test
  *   A ConfigTest entity.
  */
 function config_test_uri(ConfigTest $config_test) {
@@ -156,7 +136,7 @@ function config_test_load($id) {
 /**
  * Saves a ConfigTest object.
  *
- * @param Drupal\config_test\ConfigTest $config_test
+ * @param Drupal\config_test\Plugin\Core\Entity\ConfigTest $config_test
  *   The ConfigTest object to save.
  */
 function config_test_save(ConfigTest $config_test) {
@@ -184,7 +164,7 @@ function config_test_list_page() {
 /**
  * Form constructor to add or edit a ConfigTest object.
  *
- * @param Drupal\config_test\ConfigTest $config_test
+ * @param Drupal\config_test\Plugin\Core\Entity\ConfigTest $config_test
  *   (optional) An existing ConfigTest object to edit. If omitted, the form
  *   creates a new ConfigTest.
  */
@@ -260,7 +240,7 @@ function config_test_form_submit($form, &$form_state) {
 /**
  * Form constructor to delete a ConfigTest object.
  *
- * @param Drupal\config_test\ConfigTest $config_test
+ * @param Drupal\config_test\Plugin\Core\Entity\ConfigTest $config_test
  *   The ConfigTest object to delete.
  */
 function config_test_delete_form($form, &$form_state, ConfigTest $config_test) {
diff --git a/core/modules/config/tests/config_test/lib/Drupal/config_test/ConfigTest.php b/core/modules/config/tests/config_test/lib/Drupal/config_test/ConfigTest.php
deleted file mode 100644
index e1df5c4..0000000
--- a/core/modules/config/tests/config_test/lib/Drupal/config_test/ConfigTest.php
+++ /dev/null
@@ -1,45 +0,0 @@
-<?php
-
-/**
- * @file
- * Definition of Drupal\config_test\ConfigTest.
- */
-
-namespace Drupal\config_test;
-
-use Drupal\Core\Config\Entity\ConfigEntityBase;
-
-/**
- * Defines the ConfigTest configuration entity.
- */
-class ConfigTest extends ConfigEntityBase {
-
-  /**
-   * The machine name for the configuration entity.
-   *
-   * @var string
-   */
-  public $id;
-
-  /**
-   * The UUID for the configuration entity.
-   *
-   * @var string
-   */
-  public $uuid;
-
-  /**
-   * The human-readable name of the configuration entity.
-   *
-   * @var string
-   */
-  public $label;
-
-  /**
-   * The image style to use.
-   *
-   * @var string
-   */
-  public $style;
-
-}
diff --git a/core/modules/config/tests/config_test/lib/Drupal/config_test/Plugin/Core/Entity/ConfigTest.php b/core/modules/config/tests/config_test/lib/Drupal/config_test/Plugin/Core/Entity/ConfigTest.php
new file mode 100644
index 0000000..d7947d3
--- /dev/null
+++ b/core/modules/config/tests/config_test/lib/Drupal/config_test/Plugin/Core/Entity/ConfigTest.php
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\config_test\Plugin\Core\Entity\ConfigTest.
+ */
+
+namespace Drupal\config_test\Plugin\Core\Entity;
+
+use Drupal\Core\Config\Entity\ConfigEntityBase;
+use Drupal\Core\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * Defines the ConfigTest configuration entity.
+ *
+ * @Plugin(
+ *   id = "config_test",
+ *   label = @Translation("Test configuration"),
+ *   module = "config_test",
+ *   controller_class = "Drupal\Core\Config\Entity\ConfigStorageController",
+ *   list_controller_class = "Drupal\Core\Config\Entity\ConfigEntityListController",
+ *   uri_callback = "config_test_uri",
+ *   config_prefix = "config_test.dynamic",
+ *   entity_keys = {
+ *     "id" = "id",
+ *     "label" = "label",
+ *     "uuid" = "uuid"
+ *   }
+ * )
+ */
+class ConfigTest extends ConfigEntityBase {
+
+  /**
+   * The machine name for the configuration entity.
+   *
+   * @var string
+   */
+  public $id;
+
+  /**
+   * The UUID for the configuration entity.
+   *
+   * @var string
+   */
+  public $uuid;
+
+  /**
+   * The human-readable name of the configuration entity.
+   *
+   * @var string
+   */
+  public $label;
+
+  /**
+   * The image style to use.
+   *
+   * @var string
+   */
+  public $style;
+
+}
diff --git a/core/modules/contact/contact.admin.inc b/core/modules/contact/contact.admin.inc
index 57d6ce3..1adfa1a 100644
--- a/core/modules/contact/contact.admin.inc
+++ b/core/modules/contact/contact.admin.inc
@@ -5,7 +5,7 @@
  * Admin page callbacks for the Contact module.
  */
 
-use Drupal\contact\Category;
+use Drupal\contact\Plugin\Core\Entity\Category;
 
 /**
  * Page callback: Lists contact categories.
@@ -27,7 +27,7 @@ function contact_category_add() {
 /**
  * Form constructor for the contact category deletion form.
  *
- * @param Drupal\contact\Category $category
+ * @param Drupal\contact\Plugin\Core\Entity\Category $category
  *   The contact category to be deleted.
  *
  * @see contact_menu()
diff --git a/core/modules/contact/contact.module b/core/modules/contact/contact.module
index 8d73765..94eea77 100644
--- a/core/modules/contact/contact.module
+++ b/core/modules/contact/contact.module
@@ -5,7 +5,7 @@
  * Enables the use of personal and site-wide contact forms.
  */
 
-use Drupal\contact\Category;
+use Drupal\contact\Plugin\Core\Entity\Category;
 
 /**
  * Implements hook_help().
@@ -197,35 +197,12 @@ function contact_config_import_delete($name, $new_config, $old_config) {
 }
 
 /**
- * Implements hook_entity_info().
- */
-function contact_entity_info() {
-  $types['contact_category'] = array(
-    'label' => 'Category',
-    'entity class' => 'Drupal\contact\Category',
-    'controller class' => 'Drupal\Core\Config\Entity\ConfigStorageController',
-    'list controller class' => 'Drupal\contact\CategoryListController',
-    'form controller class' => array(
-      'default' => 'Drupal\contact\CategoryFormController',
-    ),
-    'uri callback' => 'contact_category_uri',
-    'config prefix' => 'contact.category',
-    'entity keys' => array(
-      'id' => 'id',
-      'label' => 'label',
-      'uuid' => 'uuid',
-    ),
-  );
-  return $types;
-}
-
-/**
  * Loads a contact category.
  *
  * @param $id
  *   The ID of the contact category to load.
  *
- * @return Drupal\contact\Category|false
+ * @return Drupal\contact\Plugin\Core\Entity\Category|false
  *   A Category object or FALSE if the requested $id does not exist.
  */
 function contact_category_load($id) {
diff --git a/core/modules/contact/lib/Drupal/contact/Category.php b/core/modules/contact/lib/Drupal/contact/Category.php
deleted file mode 100644
index 1a34479..0000000
--- a/core/modules/contact/lib/Drupal/contact/Category.php
+++ /dev/null
@@ -1,59 +0,0 @@
-<?php
-
-/**
- * @file
- * Definition of Drupal\contact\Category.
- */
-
-namespace Drupal\contact;
-
-use Drupal\Core\Config\Entity\ConfigEntityBase;
-
-/**
- * Defines the contact category entity.
- */
-class Category extends ConfigEntityBase {
-
-  /**
-   * The category ID.
-   *
-   * @var string
-   */
-  public $id;
-
-  /**
-   * The category UUID.
-   *
-   * @var string
-   */
-  public $uuid;
-
-  /**
-   * The category label.
-   *
-   * @var string
-   */
-  public $label;
-
-  /**
-   * List of recipient e-mail addresses.
-   *
-   * @var array
-   */
-  public $recipients = array();
-
-  /**
-   * An auto-reply message to send to the message author.
-   *
-   * @var string
-   */
-  public $reply = '';
-
-  /**
-   * Weight of this category (used for sorting).
-   *
-   * @var int
-   */
-  public $weight = 0;
-
-}
diff --git a/core/modules/contact/lib/Drupal/contact/Plugin/Core/Entity/Category.php b/core/modules/contact/lib/Drupal/contact/Plugin/Core/Entity/Category.php
new file mode 100644
index 0000000..c2d456b
--- /dev/null
+++ b/core/modules/contact/lib/Drupal/contact/Plugin/Core/Entity/Category.php
@@ -0,0 +1,79 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\contact\Plugin\Core\Entity\Category.
+ */
+
+namespace Drupal\contact\Plugin\Core\Entity;
+
+use Drupal\Core\Config\Entity\ConfigEntityBase;
+use Drupal\Core\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * Defines the contact category entity.
+ *
+ * @Plugin(
+ *   id = "contact_category",
+ *   label = @Translation("Category"),
+ *   module = "contact",
+ *   controller_class = "Drupal\Core\Config\Entity\ConfigStorageController",
+ *   list_controller_class = "Drupal\contact\CategoryListController",
+ *   form_controller_class = {
+ *     "default" = "Drupal\contact\CategoryFormController"
+ *   },
+ *   uri_callback = "contact_category_uri",
+ *   config_prefix = "contact.category",
+ *   entity_keys = {
+ *     "id" = "id",
+ *     "label" = "label",
+ *     "uuid" = "uuid"
+ *   }
+ * )
+ */
+class Category extends ConfigEntityBase {
+
+  /**
+   * The category ID.
+   *
+   * @var string
+   */
+  public $id;
+
+  /**
+   * The category UUID.
+   *
+   * @var string
+   */
+  public $uuid;
+
+  /**
+   * The category label.
+   *
+   * @var string
+   */
+  public $label;
+
+  /**
+   * List of recipient e-mail addresses.
+   *
+   * @var array
+   */
+  public $recipients = array();
+
+  /**
+   * An auto-reply message to send to the message author.
+   *
+   * @var string
+   */
+  public $reply = '';
+
+  /**
+   * Weight of this category (used for sorting).
+   *
+   * @var int
+   */
+  public $weight = 0;
+
+}
diff --git a/core/modules/field/field.attach.inc b/core/modules/field/field.attach.inc
index d267546..bbb82fe 100644
--- a/core/modules/field/field.attach.inc
+++ b/core/modules/field/field.attach.inc
@@ -60,19 +60,19 @@
  * of the fieldable entity, such as 'node' or 'user', and $entity is the entity
  * itself.
  *
- * hook_entity_info() is the central place for entity types to define if and how
+ * An entity plugin's annotation is how entity types define if and how
  * Field API should operate on their entity objects. Notably, the 'fieldable'
  * property needs to be set to TRUE.
  *
  * The Field Attach API uses the concept of bundles: the set of fields for a
  * given entity is defined on a per-bundle basis. The collection of bundles for
- * an entity type is defined its hook_entity_info() implementation. For
+ * an entity type is defined its hook_entity_info_alter() implementation. For
  * instance, node_entity_info() exposes each node type as its own bundle. This
  * means that the set of fields of a node is determined by the node type. The
  * Field API reads the bundle name for a given entity from a particular property
- * of the entity object, and hook_entity_info() defines which property to use.
- * For instance, node_entity_info() specifies:
- * @code $info['entity keys']['bundle'] = 'type'@endcode
+ * of the entity object, and hook_entity_info_alter() defines which property to
+ * use. For instance, node_entity_info_alter() specifies:
+ * @code $info['entity_keys']['bundle'] = 'type'@endcode
  * This indicates that for a particular node object, the bundle name can be
  * found in $node->type. This property can be omitted if the entity type only
  * exposes a single bundle (all entities of this type have the same collection
@@ -900,7 +900,7 @@ function field_attach_load($entity_type, $entities, $age = FIELD_LOAD_CURRENT, $
   $info = entity_get_info($entity_type);
   // Only the most current revision of non-deleted fields for cacheable entity
   // types can be cached.
-  $cache_read = $load_current && $info['field cache'] && empty($options['deleted']);
+  $cache_read = $load_current && $info['field_cache'] && empty($options['deleted']);
   // In addition, do not write to the cache when loading a single field.
   $cache_write = $cache_read && !isset($options['field_id']);
 
@@ -1258,7 +1258,7 @@ function field_attach_update($entity_type, EntityInterface $entity) {
   module_invoke_all('field_attach_update', $entity_type, $entity);
 
   $entity_info = entity_get_info($entity_type);
-  if ($entity_info['field cache']) {
+  if ($entity_info['field_cache']) {
     cache('field')->delete("field:$entity_type:" . $entity->id());
   }
 }
@@ -1293,7 +1293,7 @@ function field_attach_delete($entity_type, $entity) {
   module_invoke_all('field_attach_delete', $entity_type, $entity);
 
   $entity_info = entity_get_info($entity_type);
-  if ($entity_info['field cache']) {
+  if ($entity_info['field_cache']) {
     cache('field')->delete("field:$entity_type:" . $entity->id());
   }
 }
diff --git a/core/modules/field/field.crud.inc b/core/modules/field/field.crud.inc
index ba2f09e..429bc6d 100644
--- a/core/modules/field/field.crud.inc
+++ b/core/modules/field/field.crud.inc
@@ -91,7 +91,7 @@ function field_create_field($field) {
   // collisions with existing entity properties, but some is better
   // than none.
   foreach (entity_get_info() as $type => $info) {
-    if (in_array($field['field_name'], $info['entity keys'])) {
+    if (in_array($field['field_name'], $info['entity_keys'])) {
       throw new FieldException(t('Attempt to create field name %name which is reserved by entity type %type.', array('%name' => $field['field_name'], '%type' => $type)));
     }
   }
diff --git a/core/modules/field/field.module b/core/modules/field/field.module
index 7fac3d2..43ae3f9 100644
--- a/core/modules/field/field.module
+++ b/core/modules/field/field.module
@@ -740,10 +740,10 @@ function field_view_mode_settings($entity_type, $bundle) {
     $bundle_settings = field_bundle_settings($entity_type, $bundle);
     $settings = $bundle_settings['view_modes'];
     // Include view modes for which nothing has been stored yet, but whose
-    // definition in hook_entity_info() specify they should use custom settings
-    // by default.
+    // definition in hook_entity_info_alter() specify they should use custom
+    // settings by default.
     $entity_info = entity_get_info($entity_type);
-    foreach ($entity_info['view modes'] as $view_mode => $view_mode_info) {
+    foreach ($entity_info['view_modes'] as $view_mode => $view_mode_info) {
       if (!isset($settings[$view_mode]['custom_settings']) && $view_mode_info['custom settings']) {
         $settings[$view_mode]['custom_settings'] = TRUE;
       }
@@ -1112,8 +1112,8 @@ function field_extract_bundle($entity_type, $bundle) {
   }
 
   $info = entity_get_info($entity_type);
-  if (is_object($bundle) && isset($info['bundle keys']['bundle']) && isset($bundle->{$info['bundle keys']['bundle']})) {
-    return $bundle->{$info['bundle keys']['bundle']};
+  if (is_object($bundle) && isset($info['bundle_keys']['bundle']) && isset($bundle->{$info['bundle_keys']['bundle']})) {
+    return $bundle->{$info['bundle_keys']['bundle']};
   }
 }
 
@@ -1300,12 +1300,12 @@ function theme_field($variables) {
 function _field_create_entity_from_ids($ids) {
   $id_properties = array();
   $info = entity_get_info($ids->entity_type);
-  $id_properties[$info['entity keys']['id']] = $ids->entity_id;
-  if (!empty($info['entity keys']['revision']) && isset($ids->revision_id)) {
-    $id_properties[$info['entity keys']['revision']] = $ids->revision_id;
+  $id_properties[$info['entity_keys']['id']] = $ids->entity_id;
+  if (!empty($info['entity_keys']['revision']) && isset($ids->revision_id)) {
+    $id_properties[$info['entity_keys']['revision']] = $ids->revision_id;
   }
-  if (!empty($info['entity keys']['bundle']) && isset($ids->bundle)) {
-    $id_properties[$info['entity keys']['bundle']] = $ids->bundle;
+  if (!empty($info['entity_keys']['bundle']) && isset($ids->bundle)) {
+    $id_properties[$info['entity_keys']['bundle']] = $ids->bundle;
   }
   return entity_create($ids->entity_type, $id_properties);
  }
diff --git a/core/modules/field/field.multilingual.inc b/core/modules/field/field.multilingual.inc
index b2e4363..73c47cb 100644
--- a/core/modules/field/field.multilingual.inc
+++ b/core/modules/field/field.multilingual.inc
@@ -29,7 +29,7 @@
  * calling field_is_translatable(), which checks the $field['translatable']
  * property returned by field_info_field(), and whether there is at least one
  * translation handler available for the field. A translation handler is a
- * module registering itself via hook_entity_info() to handle field
+ * module registering itself via hook_entity_info_alter() to handle field
  * translations.
  *
 
diff --git a/core/modules/field/lib/Drupal/field/FieldInfo.php b/core/modules/field/lib/Drupal/field/FieldInfo.php
index accbe17..b1692f7 100644
--- a/core/modules/field/lib/Drupal/field/FieldInfo.php
+++ b/core/modules/field/lib/Drupal/field/FieldInfo.php
@@ -549,7 +549,7 @@ public function prepareExtraFields($extra_fields, $entity_type, $bundle) {
     $data = $extra_fields['display'];
     foreach ($extra_fields['display'] as $name => $field_data) {
       $settings = isset($bundle_settings['extra_fields']['display'][$name]) ? $bundle_settings['extra_fields']['display'][$name] : array();
-      $view_modes = array_merge(array('default'), array_keys($entity_type_info['view modes']));
+      $view_modes = array_merge(array('default'), array_keys($entity_type_info['view_modes']));
       foreach ($view_modes as $view_mode) {
         if (isset($settings[$view_mode])) {
           $field_data['display'][$view_mode] = $settings[$view_mode];
diff --git a/core/modules/field/modules/field_sql_storage/field_sql_storage.module b/core/modules/field/modules/field_sql_storage/field_sql_storage.module
index dcd6ba1..265c117 100644
--- a/core/modules/field/modules/field_sql_storage/field_sql_storage.module
+++ b/core/modules/field/modules/field_sql_storage/field_sql_storage.module
@@ -615,7 +615,7 @@ function field_sql_storage_field_storage_query(EntityFieldQuery $query) {
         $entity_schema = drupal_get_schema($entity_base_table);
         $entity_info = entity_get_info($entity_type);
       }
-      $key = !empty($entity_info['entity keys'][$key]) ? $entity_info['entity keys'][$key] : $key;
+      $key = !empty($entity_info['entity_keys'][$key]) ? $entity_info['entity_keys'][$key] : $key;
       if (!empty($entity_schema['fields'][$key])) {
         $table = $entity_base_table;
       }
@@ -665,8 +665,8 @@ function field_sql_storage_field_storage_query(EntityFieldQuery $query) {
  */
 function _field_sql_storage_query_join_entity(Select $select_query, $entity_type, $field_base_table) {
   $entity_info = entity_get_info($entity_type);
-  $entity_base_table = $entity_info['base table'];
-  $entity_field = $entity_info['entity keys']['id'];
+  $entity_base_table = $entity_info['base_table'];
+  $entity_field = $entity_info['entity_keys']['id'];
   $select_query->join($entity_base_table, $entity_base_table, "$entity_base_table.$entity_field = $field_base_table.entity_id");
   return $entity_base_table;
 }
diff --git a/core/modules/field/tests/modules/field_test/field_test.storage.inc b/core/modules/field/tests/modules/field_test/field_test.storage.inc
index ffc919e..c6b06b6 100644
--- a/core/modules/field/tests/modules/field_test/field_test.storage.inc
+++ b/core/modules/field/tests/modules/field_test/field_test.storage.inc
@@ -319,7 +319,7 @@ function field_test_field_storage_query($field_id, $conditions, $count, &$cursor
           // If querying all revisions and the entity type has revisions, we need
           // to key the results by revision_ids.
           $entity_type = entity_get_info($row->type);
-          $id = ($load_current || empty($entity_type['entity keys']['revision'])) ? $row->entity_id : $row->revision_id;
+          $id = ($load_current || empty($entity_type['entity_keys']['revision'])) ? $row->entity_id : $row->revision_id;
 
           if (!isset($return[$row->type][$id])) {
             $return[$row->type][$id] = (object) array('entity_id' => $row->entity_id, 'revision_id' => $row->revision_id, 'bundle' => $row->bundle);
diff --git a/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/TestEntity.php b/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/TestEntity.php
deleted file mode 100644
index 25898c8..0000000
--- a/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/TestEntity.php
+++ /dev/null
@@ -1,66 +0,0 @@
-<?php
-
-/*
- * @file
- * Definition of Drupal\field_test\TestEntity.
- */
-
-namespace Drupal\field_test;
-
-use Drupal\Core\Entity\Entity;
-
-/**
- * Test entity class.
- */
-class TestEntity extends Entity {
-
-  /**
-   * Primary key.
-   *
-   * @var integer
-   */
-  public $ftid;
-
-  /**
-   * Revision key.
-   *
-   * @var integer
-   */
-  public $ftvid;
-
-  /**
-   * Bundle
-   *
-   * @var string
-   */
-  public $fttype;
-
-  /**
-   * Label property
-   *
-   * @var string
-   */
-  public $ftlabel;
-
-  /**
-   * Overrides Drupal\Core\Entity\Entity::id().
-   */
-  public function id() {
-    return $this->ftid;
-  }
-
-  /**
-   * Overrides Drupal\Core\Entity\Entity::getRevisionId().
-   */
-  public function getRevisionId() {
-    return $this->ftvid;
-  }
-
-  /**
-   * Overrides Drupal\Core\Entity\Entity::bundle().
-   */
-  public function bundle() {
-    return !empty($this->fttype) ? $this->fttype : $this->entityType();
-  }
-}
-
diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module
index 0e92ef0..fd1bdc3 100644
--- a/core/modules/field_ui/field_ui.module
+++ b/core/modules/field_ui/field_ui.module
@@ -169,7 +169,7 @@ function field_ui_menu() {
           // view modes, and use an access callback to determine which ones are
           // actually visible for a given bundle.
           $weight = 0;
-          $view_modes = array('default' => array('label' => t('Default'))) + $entity_info['view modes'];
+          $view_modes = array('default' => array('label' => t('Default'))) + $entity_info['view_modes'];
           foreach ($view_modes as $view_mode => $view_mode_info) {
             $items["$path/display/$view_mode"] = array(
               'title' => $view_mode_info['label'],
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverview.php b/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverview.php
index 086f6ee..a5e30eb 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverview.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverview.php
@@ -333,7 +333,7 @@ public function form(array $form, array &$form_state) {
     // Custom display settings.
     if ($this->view_mode == 'default') {
       $entity_info = entity_get_info($this->entity_type);
-      $view_modes = $entity_info['view modes'];
+      $view_modes = $entity_info['view_modes'];
       // Only show the settings if there is more than one view mode.
       if (count($view_modes) > 1) {
         $form['modes'] = array(
@@ -460,7 +460,7 @@ public function submit(array $form, array &$form_state) {
         // settings.
         $view_mode_settings = field_view_mode_settings($this->entity_type, $this->bundle);
         if (!empty($value) && empty($view_mode_settings[$view_mode_name]['custom_settings'])) {
-          $view_mode_label = $entity_info['view modes'][$view_mode_name]['label'];
+          $view_mode_label = $entity_info['view_modes'][$view_mode_name]['label'];
           $path = _field_ui_bundle_admin_path($this->entity_type, $this->bundle) . "/display/$view_mode_name";
           drupal_set_message(t('The %view_mode mode now uses custom display settings. You might want to <a href="@url">configure them</a>.', array('%view_mode' => $view_mode_label, '@url' => url($path))));
           // Initialize the newly customized view mode with the display settings
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageDisplayTest.php b/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageDisplayTest.php
index 96f59a2..a1c854f 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageDisplayTest.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageDisplayTest.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\field_ui\Tests;
 
-use Drupal\node\Node;
+use Drupal\node\Plugin\Core\Entity\Node;
 
 /**
  * Tests the functionality of the 'Manage display' screens.
diff --git a/core/modules/file/file.module b/core/modules/file/file.module
index 4e6c8eb..f1299a3 100644
--- a/core/modules/file/file.module
+++ b/core/modules/file/file.module
@@ -6,7 +6,7 @@
  */
 
 use Drupal\Core\Entity\EntityFieldQuery;
-use Drupal\file\File;
+use Drupal\file\Plugin\Core\Entity\File;
 use Drupal\Core\Template\Attribute;
 use Symfony\Component\HttpFoundation\JsonResponse;
 use Drupal\file\FileUsage\DatabaseFileUsageBackend;
@@ -88,30 +88,17 @@ function file_element_info() {
 }
 
 /**
- * Implements hook_entity_info().
+ * Implements hook_entity_info_alter().
  */
-function file_entity_info() {
-  return array(
-    'file' => array(
-      'label' => t('File'),
-      'base table' => 'file_managed',
-      'controller class' => 'Drupal\file\FileStorageController',
-      'entity class' => 'Drupal\file\File',
-      'entity keys' => array(
-        'id' => 'fid',
-        'label' => 'filename',
-        'uuid' => 'uuid',
-      ),
-      'view modes' => array(
-        'full' => array(
-          'label' => t('File default'),
-          'custom settings' => FALSE,
-        ),
-      ),
-      'static cache' => FALSE,
+function file_entity_info_alter(&$info) {
+  $info['file']['view_modes'] = array(
+    'full' => array(
+      'label' => t('File default'),
+      'custom settings' => FALSE,
     ),
   );
 }
+
 /**
  * Loads file entities from the database.
  *
diff --git a/core/modules/file/lib/Drupal/file/FileUsage/DatabaseFileUsageBackend.php b/core/modules/file/lib/Drupal/file/FileUsage/DatabaseFileUsageBackend.php
index ff3b0ae..eaca4bf 100644
--- a/core/modules/file/lib/Drupal/file/FileUsage/DatabaseFileUsageBackend.php
+++ b/core/modules/file/lib/Drupal/file/FileUsage/DatabaseFileUsageBackend.php
@@ -9,7 +9,7 @@
 
 use Drupal\Core\Database\Connection;
 use Drupal\Core\Database\DatabaseExceptionWrapper;
-use Drupal\file\File;
+use Drupal\file\Plugin\Core\Entity\File;
 
 /**
  * Defines the database file usage backend. This is the default Drupal backend.
diff --git a/core/modules/file/lib/Drupal/file/FileUsage/FileUsageBase.php b/core/modules/file/lib/Drupal/file/FileUsage/FileUsageBase.php
index ae2c670..9ba2ac7 100644
--- a/core/modules/file/lib/Drupal/file/FileUsage/FileUsageBase.php
+++ b/core/modules/file/lib/Drupal/file/FileUsage/FileUsageBase.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\file\FileUsage;
 
-use Drupal\file\File;
+use Drupal\file\Plugin\Core\Entity\File;
 
 /**
  * Defines the base class for database file usage backend.
diff --git a/core/modules/file/lib/Drupal/file/FileUsage/FileUsageInterface.php b/core/modules/file/lib/Drupal/file/FileUsage/FileUsageInterface.php
index 4a4b231..d9a248d 100644
--- a/core/modules/file/lib/Drupal/file/FileUsage/FileUsageInterface.php
+++ b/core/modules/file/lib/Drupal/file/FileUsage/FileUsageInterface.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\file\FileUsage;
 
-use Drupal\file\File;
+use Drupal\file\Plugin\Core\Entity\File;
 
 /**
  * File usage backend interface.
diff --git a/core/modules/file/lib/Drupal/file/File.php b/core/modules/file/lib/Drupal/file/Plugin/Core/Entity/File.php
similarity index 75%
rename from core/modules/file/lib/Drupal/file/File.php
rename to core/modules/file/lib/Drupal/file/Plugin/Core/Entity/File.php
index 9b965e3..e75d62d 100644
--- a/core/modules/file/lib/Drupal/file/File.php
+++ b/core/modules/file/lib/Drupal/file/Plugin/Core/Entity/File.php
@@ -2,15 +2,31 @@
 
 /**
  * @file
- * Definition of Drupal\file\File.
+ * Definition of Drupal\file\Plugin\Core\Entity\File.
  */
 
-namespace Drupal\file;
+namespace Drupal\file\Plugin\Core\Entity;
 
 use Drupal\Core\Entity\Entity;
+use Drupal\Core\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
 
 /**
  * Defines the file entity class.
+ *
+ * @Plugin(
+ *   id = "file",
+ *   label = @Translation("File"),
+ *   module = "file",
+ *   controller_class = "Drupal\file\FileStorageController",
+ *   base_table = "file_managed",
+ *   static_cache = FALSE,
+ *   entity_keys = {
+ *     "id" = "fid",
+ *     "label" = "filename",
+ *     "uuid" = "uuid"
+ *   }
+ * )
  */
 class File extends Entity {
 
diff --git a/core/modules/file/tests/file_module_test.module b/core/modules/file/tests/file_module_test.module
index eae577e..b962e2a 100644
--- a/core/modules/file/tests/file_module_test.module
+++ b/core/modules/file/tests/file_module_test.module
@@ -6,7 +6,7 @@
  */
 
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\file\File;
+use Drupal\file\Plugin\Core\Entity\File;
 
 /**
  * Implements hook_menu().
diff --git a/core/modules/file/tests/file_test/file_test.module b/core/modules/file/tests/file_test/file_test.module
index 46b8604..d4a4359 100644
--- a/core/modules/file/tests/file_test/file_test.module
+++ b/core/modules/file/tests/file_test/file_test.module
@@ -8,7 +8,7 @@
  * calling file_test_get_calls() or file_test_set_return().
  */
 
-use Drupal\file\File;
+use Drupal\file\Plugin\Core\Entity\File;
 
 const FILE_URL_TEST_CDN_1 = 'http://cdn1.example.com';
 const FILE_URL_TEST_CDN_2 = 'http://cdn2.example.com';
diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module
index af2daa9..f441a45 100644
--- a/core/modules/forum/forum.module
+++ b/core/modules/forum/forum.module
@@ -5,8 +5,8 @@
  * Provides discussion forums.
  */
 
-use Drupal\node\Node;
-use Drupal\taxonomy\Term;
+use Drupal\node\Plugin\Core\Entity\Node;
+use Drupal\taxonomy\Plugin\Core\Entity\Term;
 
 /**
  * Implements hook_help().
@@ -220,8 +220,8 @@ function forum_menu_local_tasks_alter(&$data, $router_item, $root_path) {
 function forum_entity_info_alter(&$info) {
   // Take over URI construction for taxonomy terms that are forums.
   if ($vid = config('forum.settings')->get('vocabulary')) {
-    // Within hook_entity_info(), we can't invoke entity_load() as that would
-    // cause infinite recursion, so we call taxonomy_vocabulary_get_names()
+    // Within hook_entity_info_alter(), we can't invoke entity_load() as that
+    // would cause infinite recursion, so we call taxonomy_vocabulary_get_names()
     // instead of taxonomy_vocabulary_load(). All we need is the machine name
     // of $vid, so retrieving and iterating all the vocabulary names is somewhat
     // inefficient, but entity info is cached across page requests, and an
@@ -229,7 +229,7 @@ function forum_entity_info_alter(&$info) {
     // and is done as part of taxonomy_entity_info() anyway.
     foreach (taxonomy_vocabulary_get_names() as $machine_name => $vocabulary) {
       if ($vid == $vocabulary->vid) {
-        $info['taxonomy_term']['bundles'][$machine_name]['uri callback'] = 'forum_uri';
+        $info['taxonomy_term']['bundles'][$machine_name]['uri_callback'] = 'forum_uri';
       }
     }
   }
diff --git a/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php b/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php
index b747a68..25b2060 100644
--- a/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php
+++ b/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\forum\Tests;
 
-use Drupal\node\Node;
+use Drupal\node\Plugin\Core\Entity\Node;
 use Drupal\simpletest\WebTestBase;
 
 /**
diff --git a/core/modules/image/image.module b/core/modules/image/image.module
index 9861931..bb5fe8e 100644
--- a/core/modules/image/image.module
+++ b/core/modules/image/image.module
@@ -9,7 +9,7 @@
 use Symfony\Component\HttpFoundation\StreamedResponse;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 use Drupal\Component\Uuid\Uuid;
-use Drupal\file\File;
+use Drupal\file\Plugin\Core\Entity\File;
 
 /**
  * Image style constant for user presets in the database.
diff --git a/core/modules/menu/menu.module b/core/modules/menu/menu.module
index cee4ba5..81fb51f 100644
--- a/core/modules/menu/menu.module
+++ b/core/modules/menu/menu.module
@@ -11,7 +11,7 @@
  * URLs to be added to the main site navigation menu.
  */
 
-use Drupal\node\Node;
+use Drupal\node\Plugin\Core\Entity\Node;
 
 use Symfony\Component\HttpFoundation\JsonResponse;
 
diff --git a/core/modules/node/lib/Drupal/node/Node.php b/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php
similarity index 81%
rename from core/modules/node/lib/Drupal/node/Node.php
rename to core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php
index 45d93f0..b828c71 100644
--- a/core/modules/node/lib/Drupal/node/Node.php
+++ b/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php
@@ -2,16 +2,40 @@
 
 /**
  * @file
- * Definition of Drupal\node\Node.
+ * Definition of Drupal\node\Plugin\Core\Entity\Node.
  */
 
-namespace Drupal\node;
+namespace Drupal\node\Plugin\Core\Entity;
 
 use Drupal\Core\Entity\ContentEntityInterface;
 use Drupal\Core\Entity\Entity;
+use Drupal\Core\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
 
 /**
  * Defines the node entity class.
+ *
+ * @Plugin(
+ *   id = "node",
+ *   label = @Translation("Node"),
+ *   module = "node",
+ *   controller_class = "Drupal\node\NodeStorageController",
+ *   render_controller_class = "Drupal\node\NodeRenderController",
+ *   form_controller_class = {
+ *     "default" = "Drupal\node\NodeFormController"
+ *   },
+ *   base_table = "node",
+ *   revision_table = "node_revision",
+ *   uri_callback = "node_uri",
+ *   fieldable = TRUE,
+ *   entity_keys = {
+ *     "id" = "nid",
+ *     "revision" = "vid",
+ *     "bundle" = "type",
+ *     "label" = "title",
+ *     "uuid" = "uuid"
+ *   }
+ * )
  */
 class Node extends Entity implements ContentEntityInterface {
 
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 55989de..ffc976e 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -15,8 +15,8 @@
 use Drupal\Core\Database\Query\SelectExtender;
 use Drupal\Core\Database\Query\SelectInterface;
 use Drupal\Core\Template\Attribute;
-use Drupal\node\Node;
-use Drupal\file\File;
+use Drupal\node\Plugin\Core\Entity\Node;
+use Drupal\file\Plugin\Core\Entity\File;
 use Drupal\Core\Entity\EntityInterface;
 
 /**
@@ -191,59 +191,36 @@ function node_cron() {
 }
 
 /**
- * Implements hook_entity_info().
+ * Implements hook_entity_info_alter().
  */
-function node_entity_info() {
-  $return = array(
-    'node' => array(
-      'label' => t('Node'),
-      'entity class' => 'Drupal\node\Node',
-      'controller class' => 'Drupal\node\NodeStorageController',
-      'form controller class' => array(
-        'default' => 'Drupal\node\NodeFormController',
-      ),
-      'base table' => 'node',
-      'revision table' => 'node_revision',
-      'uri callback' => 'node_uri',
-      'fieldable' => TRUE,
-      'entity keys' => array(
-        'id' => 'nid',
-        'revision' => 'vid',
-        'bundle' => 'type',
-        'label' => 'title',
-        'uuid' => 'uuid',
-      ),
-      'bundle keys' => array(
-        'bundle' => 'type',
-      ),
-      'bundles' => array(),
-      'render controller class' => 'Drupal\node\NodeRenderController',
-      'view modes' => array(
-        'full' => array(
-          'label' => t('Full content'),
-          'custom settings' => FALSE,
-        ),
-        'teaser' => array(
-          'label' => t('Teaser'),
-          'custom settings' => TRUE,
-        ),
-        'rss' => array(
-          'label' => t('RSS'),
-          'custom settings' => FALSE,
-        ),
-      ),
+function node_entity_info_alter(&$info) {
+  $info['node']['bundle_keys'] = array(
+    'bundle' => 'type',
+  );
+  $info['node']['view_modes'] = array(
+    'full' => array(
+      'label' => t('Full content'),
+      'custom settings' => FALSE,
+    ),
+    'teaser' => array(
+      'label' => t('Teaser'),
+      'custom settings' => TRUE,
+    ),
+    'rss' => array(
+      'label' => t('RSS'),
+      'custom settings' => FALSE,
     ),
   );
 
   // Add a translation handler for fields if the language module is enabled.
   if (module_exists('language')) {
-    $return['node']['translation']['node'] = TRUE;
+    $info['node']['translation']['node'] = TRUE;
   }
 
   // Search integration is provided by node.module, so search-related
   // view modes for nodes are defined here and not in search.module.
   if (module_exists('search')) {
-    $return['node']['view modes'] += array(
+    $info['node']['view_modes'] += array(
       'search_index' => array(
         'label' => t('Search index'),
         'custom settings' => FALSE,
@@ -259,7 +236,7 @@ function node_entity_info() {
   // messages, and the path to attach Field admin pages to.
   node_type_cache_reset();
   foreach (node_type_get_names() as $type => $name) {
-    $return['node']['bundles'][$type] = array(
+    $info['node']['bundles'][$type] = array(
       'label' => $name,
       'admin' => array(
         'path' => 'admin/structure/types/manage/%node_type',
@@ -269,8 +246,6 @@ function node_entity_info() {
       ),
     );
   }
-
-  return $return;
 }
 
 /**
diff --git a/core/modules/node/node.pages.inc b/core/modules/node/node.pages.inc
index a3afa7f..3a86060 100644
--- a/core/modules/node/node.pages.inc
+++ b/core/modules/node/node.pages.inc
@@ -9,7 +9,7 @@
  * @see node_menu()
  */
 
-use Drupal\node\Node;
+use Drupal\node\Plugin\Core\Entity\Node;
 
 /**
  * Page callback: Presents the node editing form.
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 a503217..bcd5a71 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
@@ -9,7 +9,7 @@
 
 use Drupal\Core\Entity\EntityFieldQuery;
 
-use Drupal\node\Node;
+use Drupal\node\Plugin\Core\Entity\Node;
 
 /**
  * Implements hook_node_grants().
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 1686ff0..d3aa004 100644
--- a/core/modules/node/tests/modules/node_test/node_test.module
+++ b/core/modules/node/tests/modules/node_test/node_test.module
@@ -6,7 +6,7 @@
  * the Node module.
  */
 
-use Drupal\node\Node;
+use Drupal\node\Plugin\Core\Entity\Node;
 
 /**
  * Implements hook_node_load().
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 570236b..c5d1129 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
@@ -6,7 +6,7 @@
  * the Node module.
  */
 
-use Drupal\node\Node;
+use Drupal\node\Plugin\Core\Entity\Node;
 
 /**
  * Implements hook_node_insert().
diff --git a/core/modules/path/path.module b/core/modules/path/path.module
index 6a69c13..942fbb6 100644
--- a/core/modules/path/path.module
+++ b/core/modules/path/path.module
@@ -5,9 +5,9 @@
  * Enables users to rename URLs.
  */
 
-use Drupal\node\Node;
+use Drupal\node\Plugin\Core\Entity\Node;
 
-use Drupal\taxonomy\Term;
+use Drupal\taxonomy\Plugin\Core\Entity\Term;
 
 /**
  * Implements hook_help().
diff --git a/core/modules/poll/poll.module b/core/modules/poll/poll.module
index c85f121..d3f8d3a 100644
--- a/core/modules/poll/poll.module
+++ b/core/modules/poll/poll.module
@@ -5,7 +5,7 @@
  * Collects votes on different topics in the form of multiple choice questions.
  */
 
-use Drupal\node\Node;
+use Drupal\node\Plugin\Core\Entity\Node;
 
 /**
  * Implements hook_help().
diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/TrackerAttributesTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/TrackerAttributesTest.php
index e4f6fe4..d92d106 100644
--- a/core/modules/rdf/lib/Drupal/rdf/Tests/TrackerAttributesTest.php
+++ b/core/modules/rdf/lib/Drupal/rdf/Tests/TrackerAttributesTest.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\rdf\Tests;
 
-use Drupal\node\Node;
+use Drupal\node\Plugin\Core\Entity\Node;
 use Drupal\simpletest\WebTestBase;
 
 /**
diff --git a/core/modules/search/search.module b/core/modules/search/search.module
index 315ae7a..a32b5c3 100644
--- a/core/modules/search/search.module
+++ b/core/modules/search/search.module
@@ -5,7 +5,7 @@
  * Enables site-wide keyword searching.
  */
 
-use Drupal\node\Node;
+use Drupal\node\Plugin\Core\Entity\Node;
 
 /**
  * Matches all 'N' Unicode character classes (numbers)
diff --git a/core/modules/statistics/statistics.module b/core/modules/statistics/statistics.module
index 8469e52..f11f3ed 100644
--- a/core/modules/statistics/statistics.module
+++ b/core/modules/statistics/statistics.module
@@ -5,7 +5,7 @@
  * Logs and displays access statistics for a site.
  */
 
-use Drupal\node\Node;
+use Drupal\node\Plugin\Core\Entity\Node;
 
 /**
  * Implements hook_help().
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiInfoTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiInfoTest.php
index 2af085b..b5a5cd5 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiInfoTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiInfoTest.php
@@ -52,6 +52,6 @@ function testEntityInfoCacheWatchdog() {
     module_enable(array('entity_cache_test'));
     $info = variable_get('entity_cache_test');
     $this->assertEqual($info['label'], 'Entity Cache Test', 'Entity info label is correct.');
-    $this->assertEqual($info['controller class'], 'Drupal\Core\Entity\DatabaseStorageController', 'Entity controller class info is correct.');
+    $this->assertEqual($info['controller_class'], 'Drupal\Core\Entity\DatabaseStorageController', 'Entity controller class info is correct.');
   }
 }
diff --git a/core/modules/system/tests/modules/bundle_test/lib/Drupal/bundle_test/TestFileUsage.php b/core/modules/system/tests/modules/bundle_test/lib/Drupal/bundle_test/TestFileUsage.php
index 12cc137..0ee5f2d 100644
--- a/core/modules/system/tests/modules/bundle_test/lib/Drupal/bundle_test/TestFileUsage.php
+++ b/core/modules/system/tests/modules/bundle_test/lib/Drupal/bundle_test/TestFileUsage.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\bundle_test;
 
-use Drupal\file\File;
+use Drupal\file\Plugin\Core\Entity\File;
 
 class TestFileUsage extends FileUsageBase {
 
diff --git a/core/modules/system/tests/modules/entity_cache_test_dependency/entity_cache_test_dependency.module b/core/modules/system/tests/modules/entity_cache_test_dependency/entity_cache_test_dependency.module
index 2d4b3be..6db46d7 100644
--- a/core/modules/system/tests/modules/entity_cache_test_dependency/entity_cache_test_dependency.module
+++ b/core/modules/system/tests/modules/entity_cache_test_dependency/entity_cache_test_dependency.module
@@ -6,12 +6,8 @@
  */
 
 /**
- * Implements hook_entity_info().
+ * Implements hook_entity_info_alter().
  */
-function entity_cache_test_dependency_entity_info() {
-  return array(
-    'entity_cache_test' => array(
-      'label' => variable_get('entity_cache_test_label', 'Entity Cache Test'),
-    ),
-  );
+function entity_cache_test_dependency_entity_info_alter(&$info) {
+  $info['entity_cache_test']['label'] = variable_get('entity_cache_test_label', 'Entity Cache Test');
 }
diff --git a/core/modules/system/tests/modules/taxonomy_test/taxonomy_test.module b/core/modules/system/tests/modules/taxonomy_test/taxonomy_test.module
index 63f6406..b2e3adb 100644
--- a/core/modules/system/tests/modules/taxonomy_test/taxonomy_test.module
+++ b/core/modules/system/tests/modules/taxonomy_test/taxonomy_test.module
@@ -7,7 +7,7 @@
  * @see Drupal\taxonomy\Tests\TaxonomyHooksTestCase::testTaxonomyTermHooks()
  */
 
-use Drupal\taxonomy\Term;
+use Drupal\taxonomy\Plugin\Core\Entity\Term;
 
 /**
  * Implements hook_taxonomy_term_load().
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Term.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Term.php
similarity index 71%
rename from core/modules/taxonomy/lib/Drupal/taxonomy/Term.php
rename to core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Term.php
index 42ad4c5..3b4b121 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Term.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Term.php
@@ -2,16 +2,38 @@
 
 /**
  * @file
- * Definition of Drupal\taxonomy\Term.
+ * Definition of Drupal\taxonomy\Plugin\Core\Entity\Term.
  */
 
-namespace Drupal\taxonomy;
+namespace Drupal\taxonomy\Plugin\Core\Entity;
 
 use Drupal\Core\Entity\ContentEntityInterface;
 use Drupal\Core\Entity\Entity;
+use Drupal\Core\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
 
 /**
  * Defines the taxonomy term entity.
+ *
+ * @Plugin(
+ *   id = "taxonomy_term",
+ *   label = @Translation("Taxonomy term"),
+ *   module = "taxonomy",
+ *   controller_class = "Drupal\taxonomy\TermStorageController",
+ *   render_controller_class = "Drupal\taxonomy\TermRenderController",
+ *   form_controller_class = {
+ *     "default" = "Drupal\taxonomy\TermFormController"
+ *   },
+ *   base_table = "taxonomy_term_data",
+ *   uri_callback = "taxonomy_term_uri",
+ *   fieldable = TRUE,
+ *   entity_keys = {
+ *     "id" = "tid",
+ *     "bundle" = "vocabulary_machine_name",
+ *     "label" = "name",
+ *     "uuid" = "uuid"
+ *   }
+ * )
  */
 class Term extends Entity implements ContentEntityInterface {
 
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Vocabulary.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Vocabulary.php
similarity index 64%
rename from core/modules/taxonomy/lib/Drupal/taxonomy/Vocabulary.php
rename to core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Vocabulary.php
index e32f285..beee8d1 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Vocabulary.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Vocabulary.php
@@ -2,15 +2,32 @@
 
 /**
  * @file
- * Definition of Drupal\taxonomy\Vocabulary.
+ * Definition of Drupal\taxonomy\Plugin\Core\Entity\Vocabulary.
  */
 
-namespace Drupal\taxonomy;
+namespace Drupal\taxonomy\Plugin\Core\Entity;
 
 use Drupal\Core\Entity\Entity;
+use Drupal\Core\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
 
 /**
  * Defines the taxonomy vocabulary entity.
+ *
+ * @Plugin(
+ *   id = "taxonomy_vocabulary",
+ *   label = @Translation("Taxonomy vocabulary"),
+ *   module = "taxonomy",
+ *   controller_class = "Drupal\taxonomy\VocabularyStorageController",
+ *   form_controller_class = {
+ *     "default" = "Drupal\taxonomy\VocabularyFormController"
+ *   },
+ *   base_table = "taxonomy_vocabulary",
+ *   entity_keys = {
+ *     "id" = "vid",
+ *     "label" = "name"
+ *   }
+ * )
  */
 class Vocabulary extends Entity {
 
diff --git a/core/modules/taxonomy/taxonomy.admin.inc b/core/modules/taxonomy/taxonomy.admin.inc
index 273b35c..61023d5 100644
--- a/core/modules/taxonomy/taxonomy.admin.inc
+++ b/core/modules/taxonomy/taxonomy.admin.inc
@@ -5,8 +5,8 @@
  * Administrative page callbacks for the taxonomy module.
  */
 
-use Drupal\taxonomy\Term;
-use Drupal\taxonomy\Vocabulary;
+use Drupal\taxonomy\Plugin\Core\Entity\Term;
+use Drupal\taxonomy\Plugin\Core\Entity\Vocabulary;
 
 /**
  * Form builder to list and manage vocabularies.
@@ -131,7 +131,7 @@ function taxonomy_vocabulary_add() {
  * Display a tree of all the terms in a vocabulary, with options to edit
  * each one. The form is made drag and drop by the theme function.
  *
- * @param Drupal\taxonomy\Vocabulary $vocabulary
+ * @param Drupal\taxonomy\Plugin\Core\Entity\Vocabulary $vocabulary
  *   The taxonomy vocabulary entity to list terms for.
  *
  * @ingroup forms
diff --git a/core/modules/taxonomy/taxonomy.api.php b/core/modules/taxonomy/taxonomy.api.php
index 6657624..1eb6bf2 100644
--- a/core/modules/taxonomy/taxonomy.api.php
+++ b/core/modules/taxonomy/taxonomy.api.php
@@ -34,10 +34,10 @@ function hook_taxonomy_vocabulary_load(array $vocabularies) {
  * Modules implementing this hook can act on the vocabulary object before it is
  * inserted or updated.
  *
- * @param Drupal\taxonomy\Vocabulary $vocabulary
+ * @param Drupal\taxonomy\Plugin\Core\Entity\Vocabulary $vocabulary
  *   A taxonomy vocabulary entity.
  */
-function hook_taxonomy_vocabulary_presave(Drupal\taxonomy\Vocabulary $vocabulary) {
+function hook_taxonomy_vocabulary_presave(Drupal\taxonomy\Plugin\Core\Entity\Vocabulary $vocabulary) {
   $vocabulary->foo = 'bar';
 }
 
@@ -47,10 +47,10 @@ function hook_taxonomy_vocabulary_presave(Drupal\taxonomy\Vocabulary $vocabulary
  * Modules implementing this hook can act on the vocabulary object when saved
  * to the database.
  *
- * @param Drupal\taxonomy\Vocabulary $vocabulary
+ * @param Drupal\taxonomy\Plugin\Core\Entity\Vocabulary $vocabulary
  *   A taxonomy vocabulary entity.
  */
-function hook_taxonomy_vocabulary_insert(Drupal\taxonomy\Vocabulary $vocabulary) {
+function hook_taxonomy_vocabulary_insert(Drupal\taxonomy\Plugin\Core\Entity\Vocabulary $vocabulary) {
   if ($vocabulary->synonyms) {
     variable_set('taxonomy_' . $vocabulary->vid . '_synonyms', TRUE);
   }
@@ -61,10 +61,10 @@ function hook_taxonomy_vocabulary_insert(Drupal\taxonomy\Vocabulary $vocabulary)
  *
  * Modules implementing this hook can act on the vocabulary object when updated.
  *
- * @param Drupal\taxonomy\Vocabulary $vocabulary
+ * @param Drupal\taxonomy\Plugin\Core\Entity\Vocabulary $vocabulary
  *   A taxonomy vocabulary entity.
  */
-function hook_taxonomy_vocabulary_update(Drupal\taxonomy\Vocabulary $vocabulary) {
+function hook_taxonomy_vocabulary_update(Drupal\taxonomy\Plugin\Core\Entity\Vocabulary $vocabulary) {
   $status = $vocabulary->synonyms ? TRUE : FALSE;
   if ($vocabulary->synonyms) {
     variable_set('taxonomy_' . $vocabulary->vid . '_synonyms', $status);
@@ -78,13 +78,13 @@ function hook_taxonomy_vocabulary_update(Drupal\taxonomy\Vocabulary $vocabulary)
  * field_attach_delete_bundle() is called and before the vocabulary is actually
  * removed from the database.
  *
- * @param Drupal\taxonomy\Vocabulary $vocabulary
+ * @param Drupal\taxonomy\Plugin\Core\Entity\Vocabulary $vocabulary
  *   The taxonomy vocabulary entity that is about to be deleted.
  *
  * @see hook_taxonomy_vocabulary_delete()
  * @see taxonomy_vocabulary_delete()
  */
-function hook_taxonomy_vocabulary_predelete(Drupal\taxonomy\Vocabulary $vocabulary) {
+function hook_taxonomy_vocabulary_predelete(Drupal\taxonomy\Plugin\Core\Entity\Vocabulary $vocabulary) {
   if (variable_get('taxonomy_' . $vocabulary->vid . '_synonyms', FALSE)) {
     variable_del('taxonomy_' . $vocabulary->vid . '_synonyms');
   }
@@ -97,13 +97,13 @@ function hook_taxonomy_vocabulary_predelete(Drupal\taxonomy\Vocabulary $vocabula
  * field_attach_delete_bundle() has been called and after the vocabulary has
  * been removed from the database.
  *
- * @param Drupal\taxonomy\Vocabulary $vocabulary
+ * @param Drupal\taxonomy\Plugin\Core\Entity\Vocabulary $vocabulary
  *   The taxonomy vocabulary entity that has been deleted.
  *
  * @see hook_taxonomy_vocabulary_predelete()
  * @see taxonomy_vocabulary_delete()
  */
-function hook_taxonomy_vocabulary_delete(Drupal\taxonomy\Vocabulary $vocabulary) {
+function hook_taxonomy_vocabulary_delete(Drupal\taxonomy\Plugin\Core\Entity\Vocabulary $vocabulary) {
   if (variable_get('taxonomy_' . $vocabulary->vid . '_synonyms', FALSE)) {
     variable_del('taxonomy_' . $vocabulary->vid . '_synonyms');
   }
diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module
index 874c78a..147cc36 100644
--- a/core/modules/taxonomy/taxonomy.module
+++ b/core/modules/taxonomy/taxonomy.module
@@ -5,9 +5,9 @@
  * Enables the organization of content into categories.
  */
 
-use Drupal\node\Node;
-use Drupal\taxonomy\Term;
-use Drupal\taxonomy\Vocabulary;
+use Drupal\node\Plugin\Core\Entity\Node;
+use Drupal\taxonomy\Plugin\Core\Entity\Term;
+use Drupal\taxonomy\Plugin\Core\Entity\Vocabulary;
 use Drupal\Core\Entity\EntityInterface;
 
 /**
@@ -106,42 +106,21 @@ function taxonomy_permission() {
 }
 
 /**
- * Implements hook_entity_info().
+ * Implements hook_entity_info_alter().
  */
-function taxonomy_entity_info() {
-  $return = array(
-    'taxonomy_term' => array(
-      'label' => t('Taxonomy term'),
-      'entity class' => 'Drupal\taxonomy\Term',
-      'controller class' => 'Drupal\taxonomy\TermStorageController',
-      'form controller class' => array(
-        'default' => 'Drupal\taxonomy\TermFormController',
-      ),
-      'base table' => 'taxonomy_term_data',
-      'uri callback' => 'taxonomy_term_uri',
-      'fieldable' => TRUE,
-      'entity keys' => array(
-        'id' => 'tid',
-        'bundle' => 'vocabulary_machine_name',
-        'label' => 'name',
-        'uuid' => 'uuid',
-      ),
-      'bundle keys' => array(
-        'bundle' => 'machine_name',
-      ),
-      'bundles' => array(),
-      'render controller class' => 'Drupal\taxonomy\TermRenderController',
-      'view modes' => array(
-        // @todo View mode for display as a field (when attached to nodes etc).
-        'full' => array(
-          'label' => t('Taxonomy term page'),
-          'custom settings' => FALSE,
-        ),
-      ),
+function taxonomy_entity_info_alter(&$info) {
+  $info['taxonomy_term']['bundle_keys'] = array(
+    'bundle' => 'machine_name',
+  );
+  $info['taxonomy_term']['view_modes'] = array(
+    // @todo View mode for display as a field (when attached to nodes etc).
+    'full' => array(
+      'label' => t('Taxonomy term page'),
+      'custom settings' => FALSE,
     ),
   );
   foreach (taxonomy_vocabulary_get_names() as $machine_name => $vocabulary) {
-    $return['taxonomy_term']['bundles'][$machine_name] = array(
+    $info['taxonomy_term']['bundles'][$machine_name] = array(
       'label' => $vocabulary->name,
       'admin' => array(
         'path' => 'admin/structure/taxonomy/%taxonomy_vocabulary_machine_name',
@@ -151,28 +130,12 @@ function taxonomy_entity_info() {
       ),
     );
   }
-  $return['taxonomy_vocabulary'] = array(
-    'label' => t('Taxonomy vocabulary'),
-    'entity class' => 'Drupal\taxonomy\Vocabulary',
-    'controller class' => 'Drupal\taxonomy\VocabularyStorageController',
-    'form controller class' => array(
-      'default' => 'Drupal\taxonomy\VocabularyFormController',
-    ),
-    'base table' => 'taxonomy_vocabulary',
-    'entity keys' => array(
-      'id' => 'vid',
-      'label' => 'name',
-    ),
-    'fieldable' => FALSE,
-    'view modes' => array(
-      'full' => array(
-        'label' => t('Taxonomy vocabulary default'),
-        'custom settings' => FALSE,
-      ),
+  $info['taxonomy_vocabulary']['view_modes'] = array(
+    'full' => array(
+      'label' => t('Taxonomy vocabulary default'),
+      'custom settings' => FALSE,
     ),
   );
-
-  return $return;
 }
 
 /**
@@ -443,7 +406,7 @@ function taxonomy_term_access($op, $term) {
 /**
  * Saves a vocabulary.
  *
- * @param Drupal\taxonomy\Vocabulary $vocabulary
+ * @param Drupal\taxonomy\Plugin\Core\Entity\Vocabulary $vocabulary
  *   The taxonomy vocabulary entity to be saved.
  */
 function taxonomy_vocabulary_save(Vocabulary $vocabulary) {
@@ -507,7 +470,7 @@ function taxonomy_taxonomy_vocabulary_update(Vocabulary $vocabulary) {
  * term has multiple parents then the vocabulary will be given a hierarchy of
  * TAXONOMY_HIERARCHY_MULTIPLE.
  *
- * @param Drupal\taxonomy\Vocabulary $vocabulary
+ * @param Drupal\taxonomy\Plugin\Core\Entity\Vocabulary $vocabulary
  *   A taxonomy vocabulary entity.
  * @param $changed_term
  *   An array of the term structure that was updated.
@@ -972,7 +935,7 @@ function taxonomy_vocabulary_load_multiple(array $vids = NULL) {
  * @param int $vid
  *   The vocabulary's ID.
  *
- * @return Drupal\taxonomy\Vocabulary|false
+ * @return Drupal\taxonomy\Plugin\Core\Entity\Vocabulary|false
  *   The taxonomy vocabulary entity, if exists, FALSE otherwise. Results are
  *   statically cached.
  *
@@ -988,7 +951,7 @@ function taxonomy_vocabulary_load($vid) {
  * @param $name
  *   The vocabulary's machine name.
  *
- * @return Drupal\taxonomy\Vocabulary|false
+ * @return Drupal\taxonomy\Plugin\Core\Entity\Vocabulary|false
  *   The taxonomy vocabulary entity, if exists, FALSE otherwise. Results are
  *   statically cached.
  *
diff --git a/core/modules/taxonomy/taxonomy.pages.inc b/core/modules/taxonomy/taxonomy.pages.inc
index f1ec8ea..e57231e 100644
--- a/core/modules/taxonomy/taxonomy.pages.inc
+++ b/core/modules/taxonomy/taxonomy.pages.inc
@@ -5,8 +5,8 @@
  * Page callbacks for the taxonomy module.
  */
 
-use Drupal\taxonomy\Term;
-use Drupal\taxonomy\Vocabulary;
+use Drupal\taxonomy\Plugin\Core\Entity\Term;
+use Drupal\taxonomy\Plugin\Core\Entity\Vocabulary;
 use Symfony\Component\HttpFoundation\JsonResponse;
 
 /**
diff --git a/core/modules/tracker/tracker.module b/core/modules/tracker/tracker.module
index 7060a87..8313269 100644
--- a/core/modules/tracker/tracker.module
+++ b/core/modules/tracker/tracker.module
@@ -5,7 +5,7 @@
  * Tracks recent content posted by a user or users.
  */
 
-use Drupal\node\Node;
+use Drupal\node\Plugin\Core\Entity\Node;
 
 /**
  * Implements hook_help().
diff --git a/core/modules/translation/lib/Drupal/translation/Tests/TranslationTest.php b/core/modules/translation/lib/Drupal/translation/Tests/TranslationTest.php
index fccb453..6e1f9d5 100644
--- a/core/modules/translation/lib/Drupal/translation/Tests/TranslationTest.php
+++ b/core/modules/translation/lib/Drupal/translation/Tests/TranslationTest.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\translation\Tests;
 
-use Drupal\node\Node;
+use Drupal\node\Plugin\Core\Entity\Node;
 use Drupal\simpletest\WebTestBase;
 
 /**
diff --git a/core/modules/translation/tests/translation_test.module b/core/modules/translation/tests/translation_test.module
index 1bd0659..8c9fdf2 100644
--- a/core/modules/translation/tests/translation_test.module
+++ b/core/modules/translation/tests/translation_test.module
@@ -5,7 +5,7 @@
  * Mock module for content translation tests.
  */
 
-use Drupal\node\Node;
+use Drupal\node\Plugin\Core\Entity\Node;
 
 /**
  * Implements hook_node_insert().
diff --git a/core/modules/translation/translation.module b/core/modules/translation/translation.module
index e7f22fd..5a67213 100644
--- a/core/modules/translation/translation.module
+++ b/core/modules/translation/translation.module
@@ -19,7 +19,7 @@
  *   date (0) or needs to be updated (1).
  */
 
-use Drupal\node\Node;
+use Drupal\node\Plugin\Core\Entity\Node;
 
 /**
  * Implements hook_help().
diff --git a/core/modules/translation/translation.pages.inc b/core/modules/translation/translation.pages.inc
index e33f53e..cc94a1e 100644
--- a/core/modules/translation/translation.pages.inc
+++ b/core/modules/translation/translation.pages.inc
@@ -5,7 +5,7 @@
  * User page callbacks for the Translation module.
  */
 
-use Drupal\node\Node;
+use Drupal\node\Plugin\Core\Entity\Node;
 
 /**
  * Page callback: Displays a list of a node's translations.
diff --git a/core/modules/user/lib/Drupal/user/User.php b/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/User.php
similarity index 75%
rename from core/modules/user/lib/Drupal/user/User.php
rename to core/modules/user/lib/Drupal/user/Plugin/Core/Entity/User.php
index 2217588..4fa5b12 100644
--- a/core/modules/user/lib/Drupal/user/User.php
+++ b/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/User.php
@@ -2,15 +2,37 @@
 
 /**
  * @file
- * Definition of Drupal\user\User.
+ * Definition of Drupal\user\Plugin\Core\Entity\User.
  */
 
-namespace Drupal\user;
+namespace Drupal\user\Plugin\Core\Entity;
 
 use Drupal\Core\Entity\Entity;
+use Drupal\Core\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
 
 /**
  * Defines the user entity class.
+ *
+ * @Plugin(
+ *   id = "user",
+ *   label = @Translation("User"),
+ *   module = "user",
+ *   controller_class = "Drupal\user\UserStorageController",
+ *   render_controller_class = "Drupal\user\UserRenderController",
+ *   form_controller_class = {
+ *     "profile" = "Drupal\user\ProfileFormController",
+ *     "register" = "Drupal\user\RegisterFormController"
+ *   },
+ *   base_table = "users",
+ *   uri_callback = "user_uri",
+ *   label_callback = "user_label",
+ *   fieldable = TRUE,
+ *   entity_keys = {
+ *     "id" = "uid",
+ *     "uuid" = "uuid"
+ *   }
+ * )
  */
 class User extends Entity {
 
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index c064427..5dcd092 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -2,7 +2,7 @@
 
 use Drupal\Core\Database\Query\SelectInterface;
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\file\File;
+use Drupal\file\Plugin\Core\Entity\File;
 use Drupal\Core\Template\Attribute;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 
@@ -139,42 +139,20 @@ function user_theme() {
 }
 
 /**
- * Implements hook_entity_info().
+ * Implements hook_entity_info_alter().
  */
-function user_entity_info() {
-  return array(
-    'user' => array(
-      'label' => t('User'),
-      'controller class' => 'Drupal\user\UserStorageController',
-      'form controller class' => array(
-        'profile' => 'Drupal\user\ProfileFormController',
-        'register' => 'Drupal\user\RegisterFormController',
-      ),
-      'base table' => 'users',
-      'uri callback' => 'user_uri',
-      'label callback' => 'user_label',
-      'fieldable' => TRUE,
-      'entity class' => 'Drupal\user\User',
-      'entity keys' => array(
-        'id' => 'uid',
-        'uuid' => 'uuid',
-      ),
-      'bundles' => array(
-        'user' => array(
-          'label' => t('User'),
-          'admin' => array(
-            'path' => 'admin/config/people/accounts',
-            'access arguments' => array('administer users'),
-          ),
-        ),
-      ),
-      'render controller class' => 'Drupal\user\UserRenderController',
-      'view modes' => array(
-        'full' => array(
-          'label' => t('User account'),
-          'custom settings' => FALSE,
-        ),
-      ),
+function user_entity_info_alter(&$info) {
+  $info['user']['bundles']['user'] = array(
+    'label' => t('User'),
+    'admin' => array(
+      'path' => 'admin/config/people/accounts',
+      'access arguments' => array('administer users'),
+    ),
+  );
+  $info['user']['view_modes'] = array(
+    'full' => array(
+      'label' => t('User account'),
+      'custom settings' => FALSE,
     ),
   );
 }
