diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php b/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php
index 8cfc060..60d0ce0 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php
@@ -438,14 +438,6 @@ public function save(EntityInterface $entity) {
   }
 
   /**
-   * {@inheritdoc}
-   */
-  public function baseFieldDefinitions() {
-    // @todo: Define abstract once all entity types have been converted.
-    return array();
-  }
-
-  /**
    * Invokes a hook on behalf of the entity.
    *
    * @param $hook
diff --git a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php b/core/lib/Drupal/Core/Entity/DatabaseStorageController.php
index bbf1ae0..ea370cf 100644
--- a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php
+++ b/core/lib/Drupal/Core/Entity/DatabaseStorageController.php
@@ -553,14 +553,6 @@ protected function invokeHook($hook, EntityInterface $entity) {
   }
 
   /**
-   * {@inheritdoc}
-   */
-  public function baseFieldDefinitions() {
-    // @todo: Define abstract once all entity types have been converted.
-    return array();
-  }
-
-  /**
    * Implements \Drupal\Core\Entity\EntityStorageControllerInterface::getQueryServiceName().
    */
   public function getQueryServiceName() {
diff --git a/core/lib/Drupal/Core/Entity/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php
index 3fc660d..0422c26 100644
--- a/core/lib/Drupal/Core/Entity/Entity.php
+++ b/core/lib/Drupal/Core/Entity/Entity.php
@@ -634,4 +634,11 @@ public function initTranslation($langcode) {
     //   http://drupal.org/node/2004244
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public static function baseFieldDefinitions($entity_type) {
+    return array();
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Entity/EntityBCDecorator.php b/core/lib/Drupal/Core/Entity/EntityBCDecorator.php
index b0be82e..bfb13ee 100644
--- a/core/lib/Drupal/Core/Entity/EntityBCDecorator.php
+++ b/core/lib/Drupal/Core/Entity/EntityBCDecorator.php
@@ -619,4 +619,11 @@ public function initTranslation($langcode) {
     $this->decorated->initTranslation($langcode);
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public static function baseFieldDefinitions($entity_type) {
+    return array();
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Entity/EntityInterface.php b/core/lib/Drupal/Core/Entity/EntityInterface.php
index e965b8e..a5c9f6e 100644
--- a/core/lib/Drupal/Core/Entity/EntityInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityInterface.php
@@ -326,4 +326,20 @@ public function isTranslatable();
    */
   public function initTranslation($langcode);
 
+  /**
+   * Defines the base fields of the entity type.
+   *
+   * @param string $entity_type
+   *   The entity type to return properties for. Useful when a single class is
+   *   used for multiple, possibly dynamic entity types.
+   *
+   * @return array
+   *   An array of entity field definitions as specified by
+   *   \Drupal\Core\Entity\EntityManager::getFieldDefinitions(), keyed by field
+   *   name.
+   *
+   * @see \Drupal\Core\Entity\EntityManager::getFieldDefinitions()
+   */
+  public static function baseFieldDefinitions($entity_type);
+
 }
diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php
index eeb1cac..f41facf 100644
--- a/core/lib/Drupal/Core/Entity/EntityManager.php
+++ b/core/lib/Drupal/Core/Entity/EntityManager.php
@@ -395,8 +395,9 @@ public function getFieldDefinitions($entity_type, $bundle = NULL) {
         $this->entityFieldInfo[$entity_type] = $cache->data;
       }
       else {
+        $class = $this->factory->getPluginClass($entity_type, $this->getDefinition($entity_type));
         $this->entityFieldInfo[$entity_type] = array(
-          'definitions' => $this->getStorageController($entity_type)->baseFieldDefinitions(),
+          'definitions' => $class::baseFieldDefinitions($entity_type),
           // Contains definitions of optional (per-bundle) fields.
           'optional' => array(),
           // An array keyed by bundle name containing the optional fields added
diff --git a/core/lib/Drupal/Core/Entity/EntityStorageControllerInterface.php b/core/lib/Drupal/Core/Entity/EntityStorageControllerInterface.php
index 24447fd..7d3c5a2 100644
--- a/core/lib/Drupal/Core/Entity/EntityStorageControllerInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityStorageControllerInterface.php
@@ -137,18 +137,6 @@ public function delete(array $entities);
   public function save(EntityInterface $entity);
 
   /**
-   * Defines the base fields of the entity type.
-   *
-   * @return array
-   *   An array of entity field definitions as specified by
-   *   \Drupal\Core\Entity\EntityManager::getFieldDefinitions(), keyed by field
-   *   name.
-   *
-   * @see \Drupal\Core\Entity\EntityManager::getFieldDefinitions()
-   */
-  public function baseFieldDefinitions();
-
-  /**
    * Gets the name of the service for the query for this entity storage.
    *
    * @return string
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Entity/Feed.php b/core/modules/aggregator/lib/Drupal/aggregator/Entity/Feed.php
index ceabe5a..610d474 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/Entity/Feed.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/Entity/Feed.php
@@ -264,4 +264,82 @@ protected function clearBlockCacheDefinitions() {
     }
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public static function baseFieldDefinitions($entity_type) {
+    $fields['fid'] = array(
+      'label' => t('ID'),
+      'description' => t('The ID of the aggregor feed.'),
+      'type' => 'integer_field',
+      'read-only' => TRUE,
+    );
+    $fields['title'] = array(
+      'label' => t('Title'),
+      'description' => t('The title of the feed.'),
+      'type' => 'string_field',
+    );
+    $fields['langcode'] = array(
+      'label' => t('Language code'),
+      'description' => t('The feed language code.'),
+      'type' => 'language_field',
+    );
+    $fields['url'] = array(
+      'label' => t('URL'),
+      'description' => t('The URL to the feed.'),
+      'type' => 'uri_field',
+    );
+    $fields['refresh'] = array(
+      'label' => t('Refresh'),
+      'description' => t('How often to check for new feed items, in seconds.'),
+      'type' => 'integer_field',
+    );
+    $fields['checked'] = array(
+      'label' => t('Checked'),
+      'description' => t('Last time feed was checked for new items, as Unix timestamp.'),
+      'type' => 'integer_field',
+    );
+    $fields['queued'] = array(
+      'label' => t('Queued'),
+      'description' => t('Time when this feed was queued for refresh, 0 if not queued.'),
+      'type' => 'integer_field',
+    );
+    $fields['link'] = array(
+      'label' => t('Link'),
+      'description' => t('The link of the feed.'),
+      'type' => 'uri_field',
+    );
+    $fields['description'] = array(
+      'label' => t('Description'),
+      'description' => t("The parent website's description that comes from the !description element in the feed.", array('!description' => '<description>')),
+      'type' => 'string_field',
+    );
+    $fields['image'] = array(
+      'label' => t('image'),
+      'description' => t('An image representing the feed.'),
+      'type' => 'uri_field',
+    );
+    $fields['hash'] = array(
+      'label' => t('Hash'),
+      'description' => t('Calculated hash of the feed data, used for validating cache.'),
+      'type' => 'string_field',
+    );
+    $fields['etag'] = array(
+      'label' => t('Etag'),
+      'description' => t('Entity tag HTTP response header, used for validating cache.'),
+      'type' => 'string_field',
+    );
+    $fields['modified'] = array(
+      'label' => t('Modified'),
+      'description' => t('When the feed was last modified, as a Unix timestamp.'),
+      'type' => 'integer_field',
+    );
+    $fields['block'] = array(
+      'label' => t('Block'),
+      'description' => t('Number of items to display in the feed’s block.'),
+      'type' => 'integer_field',
+    );
+    return $fields;
+  }
+
 }
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Entity/Item.php b/core/modules/aggregator/lib/Drupal/aggregator/Entity/Item.php
index b22e738..c24ad1e 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/Entity/Item.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/Entity/Item.php
@@ -154,4 +154,57 @@ public function postSave(EntityStorageControllerInterface $storage_controller, $
   public static function preDelete(EntityStorageControllerInterface $storage_controller, array $entities) {
     $storage_controller->deleteCategories($entities);
   }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function baseFieldDefinitions($entity_type) {
+    $fields['iid'] = array(
+      'label' => t('ID'),
+      'description' => t('The ID of the aggregor item.'),
+      'type' => 'integer_field',
+      'read-only' => TRUE,
+    );
+    $fields['fid'] = array(
+      'label' => t('Aggregator feed ID'),
+      'description' => t('The ID of the aggregator feed.'),
+      'type' => 'integer_field',
+    );
+    $fields['title'] = array(
+      'label' => t('Title'),
+      'description' => t('The title of the feed item.'),
+      'type' => 'string_field',
+    );
+    $fields['langcode'] = array(
+      'label' => t('Language code'),
+      'description' => t('The feed item language code.'),
+      'type' => 'language_field',
+    );
+    $fields['link'] = array(
+      'label' => t('Link'),
+      'description' => t('The link of the feed item.'),
+      'type' => 'uri_field',
+    );
+    $fields['author'] = array(
+      'label' => t('Author'),
+      'description' => t('The author of the feed item.'),
+      'type' => 'string_field',
+    );
+    $fields['description'] = array(
+      'label' => t('Description'),
+      'description' => t('The body of the feed item.'),
+      'type' => 'string_field',
+    );
+    $fields['timestamp'] = array(
+      'label' => t('Posted timestamp'),
+      'description' => t('Posted date of the feed item, as a Unix timestamp.'),
+      'type' => 'integer_field',
+    );
+    $fields['guid'] = array(
+      'label' => t('GUID'),
+      'description' => t('Unique identifier for the feed item.'),
+      'type' => 'string_field',
+    );
+    return $fields;
+  }
 }
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/FeedStorageController.php b/core/modules/aggregator/lib/Drupal/aggregator/FeedStorageController.php
index 7b6be0a..6db9b3f 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/FeedStorageController.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/FeedStorageController.php
@@ -28,84 +28,6 @@ protected function attachLoad(&$queried_entities, $load_revision = FALSE) {
   }
 
   /**
-   * Implements Drupal\Core\Entity\DataBaseStorageControllerNG::baseFieldDefinitions().
-   */
-  public function baseFieldDefinitions() {
-    $fields['fid'] = array(
-      'label' => t('ID'),
-      'description' => t('The ID of the aggregor feed.'),
-      'type' => 'integer_field',
-      'read-only' => TRUE,
-    );
-    $fields['title'] = array(
-      'label' => t('Title'),
-      'description' => t('The title of the feed.'),
-      'type' => 'string_field',
-    );
-    $fields['langcode'] = array(
-      'label' => t('Language code'),
-      'description' => t('The feed language code.'),
-      'type' => 'language_field',
-    );
-    $fields['url'] = array(
-      'label' => t('URL'),
-      'description' => t('The URL to the feed.'),
-      'type' => 'uri_field',
-    );
-    $fields['refresh'] = array(
-      'label' => t('Refresh'),
-      'description' => t('How often to check for new feed items, in seconds.'),
-      'type' => 'integer_field',
-    );
-    $fields['checked'] = array(
-      'label' => t('Checked'),
-      'description' => t('Last time feed was checked for new items, as Unix timestamp.'),
-      'type' => 'integer_field',
-    );
-    $fields['queued'] = array(
-      'label' => t('Queued'),
-      'description' => t('Time when this feed was queued for refresh, 0 if not queued.'),
-      'type' => 'integer_field',
-    );
-    $fields['link'] = array(
-      'label' => t('Link'),
-      'description' => t('The link of the feed.'),
-      'type' => 'uri_field',
-    );
-    $fields['description'] = array(
-      'label' => t('Description'),
-      'description' => t("The parent website's description that comes from the !description element in the feed.", array('!description' => '<description>')),
-      'type' => 'string_field',
-    );
-    $fields['image'] = array(
-      'label' => t('image'),
-      'description' => t('An image representing the feed.'),
-      'type' => 'uri_field',
-    );
-    $fields['hash'] = array(
-      'label' => t('Hash'),
-      'description' => t('Calculated hash of the feed data, used for validating cache.'),
-      'type' => 'string_field',
-    );
-    $fields['etag'] = array(
-      'label' => t('Etag'),
-      'description' => t('Entity tag HTTP response header, used for validating cache.'),
-      'type' => 'string_field',
-    );
-    $fields['modified'] = array(
-      'label' => t('Modified'),
-      'description' => t('When the feed was last modified, as a Unix timestamp.'),
-      'type' => 'integer_field',
-    );
-    $fields['block'] = array(
-      'label' => t('Block'),
-      'description' => t('Number of items to display in the feed’s block.'),
-      'type' => 'integer_field',
-    );
-    return $fields;
-  }
-
-  /**
    * {@inheritdoc}
    */
   public function loadCategories(array $feeds) {
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/ItemStorageController.php b/core/modules/aggregator/lib/Drupal/aggregator/ItemStorageController.php
index ede61e1..e17c82b 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/ItemStorageController.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/ItemStorageController.php
@@ -29,59 +29,6 @@ protected function attachLoad(&$queried_entities, $load_revision = FALSE) {
   }
 
   /**
-   * Implements Drupal\Core\Entity\DataBaseStorageControllerNG::baseFieldDefinitions().
-   */
-  public function baseFieldDefinitions() {
-    $fields['iid'] = array(
-      'label' => t('ID'),
-      'description' => t('The ID of the aggregor item.'),
-      'type' => 'integer_field',
-      'read-only' => TRUE,
-    );
-    $fields['fid'] = array(
-      'label' => t('Aggregator feed ID'),
-      'description' => t('The ID of the aggregator feed.'),
-      'type' => 'integer_field',
-    );
-    $fields['title'] = array(
-      'label' => t('Title'),
-      'description' => t('The title of the feed item.'),
-      'type' => 'string_field',
-    );
-    $fields['langcode'] = array(
-      'label' => t('Language code'),
-      'description' => t('The feed item language code.'),
-      'type' => 'language_field',
-    );
-    $fields['link'] = array(
-      'label' => t('Link'),
-      'description' => t('The link of the feed item.'),
-      'type' => 'uri_field',
-    );
-    $fields['author'] = array(
-      'label' => t('Author'),
-      'description' => t('The author of the feed item.'),
-      'type' => 'string_field',
-    );
-    $fields['description'] = array(
-      'label' => t('Description'),
-      'description' => t('The body of the feed item.'),
-      'type' => 'string_field',
-    );
-    $fields['timestamp'] = array(
-      'label' => t('Posted timestamp'),
-      'description' => t('Posted date of the feed item, as a Unix timestamp.'),
-      'type' => 'integer_field',
-    );
-    $fields['guid'] = array(
-      'label' => t('GUID'),
-      'description' => t('Unique identifier for the feed item.'),
-      'type' => 'string_field',
-    );
-    return $fields;
-  }
-
-  /**
    * {@inheritdoc}
    */
   public function loadCategories(array $entities) {
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockStorageController.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockStorageController.php
index 0698234..65142a4 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockStorageController.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockStorageController.php
@@ -36,47 +36,4 @@ protected function attachLoad(&$blocks, $load_revision = FALSE) {
     parent::attachLoad($blocks, $load_revision);
   }
 
-  /**
-   * Implements \Drupal\Core\Entity\DataBaseStorageControllerNG::basePropertyDefinitions().
-   */
-  public function baseFieldDefinitions() {
-    $properties['id'] = array(
-      'label' => t('ID'),
-      'description' => t('The custom block ID.'),
-      'type' => 'integer_field',
-      'read-only' => TRUE,
-    );
-    $properties['uuid'] = array(
-      'label' => t('UUID'),
-      'description' => t('The custom block UUID.'),
-      'type' => 'uuid_field',
-    );
-    $properties['revision_id'] = array(
-      'label' => t('Revision ID'),
-      'description' => t('The revision ID.'),
-      'type' => 'integer_field',
-    );
-    $properties['langcode'] = array(
-      'label' => t('Language code'),
-      'description' => t('The comment language code.'),
-      'type' => 'language_field',
-    );
-    $properties['info'] = array(
-      'label' => t('Subject'),
-      'description' => t('The custom block name.'),
-      'type' => 'string_field',
-    );
-    $properties['type'] = array(
-      'label' => t('Block type'),
-      'description' => t('The block type.'),
-      'type' => 'string_field',
-    );
-    $properties['log'] = array(
-      'label' => t('Revision log message'),
-      'description' => t('The revision log message.'),
-      'type' => 'string_field',
-    );
-    return $properties;
-  }
-
 }
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlock.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlock.php
index a7b3624..7106f5a 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlock.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlock.php
@@ -235,4 +235,47 @@ public function delete() {
     parent::delete();
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public static function baseFieldDefinitions($entity_type) {
+    $properties['id'] = array(
+      'label' => t('ID'),
+      'description' => t('The custom block ID.'),
+      'type' => 'integer_field',
+      'read-only' => TRUE,
+    );
+    $properties['uuid'] = array(
+      'label' => t('UUID'),
+      'description' => t('The custom block UUID.'),
+      'type' => 'uuid_field',
+    );
+    $properties['revision_id'] = array(
+      'label' => t('Revision ID'),
+      'description' => t('The revision ID.'),
+      'type' => 'integer_field',
+    );
+    $properties['langcode'] = array(
+      'label' => t('Language code'),
+      'description' => t('The comment language code.'),
+      'type' => 'language_field',
+    );
+    $properties['info'] = array(
+      'label' => t('Subject'),
+      'description' => t('The custom block name.'),
+      'type' => 'string_field',
+    );
+    $properties['type'] = array(
+      'label' => t('Block type'),
+      'description' => t('The block type.'),
+      'type' => 'string_field',
+    );
+    $properties['log'] = array(
+      'label' => t('Revision log message'),
+      'description' => t('The revision log message.'),
+      'type' => 'string_field',
+    );
+    return $properties;
+  }
+
 }
diff --git a/core/modules/comment/lib/Drupal/comment/CommentStorageController.php b/core/modules/comment/lib/Drupal/comment/CommentStorageController.php
index 8cd1a53..3dc7f2c 100644
--- a/core/modules/comment/lib/Drupal/comment/CommentStorageController.php
+++ b/core/modules/comment/lib/Drupal/comment/CommentStorageController.php
@@ -103,111 +103,6 @@ public function updateNodeStatistics($nid) {
   /**
    * {@inheritdoc}
    */
-  public function baseFieldDefinitions() {
-    $properties['cid'] = array(
-      'label' => t('ID'),
-      'description' => t('The comment ID.'),
-      'type' => 'integer_field',
-      'read-only' => TRUE,
-    );
-    $properties['uuid'] = array(
-      'label' => t('UUID'),
-      'description' => t('The comment UUID.'),
-      'type' => 'uuid_field',
-    );
-    $properties['pid'] = array(
-      'label' => t('Parent ID'),
-      'description' => t('The parent comment ID if this is a reply to a comment.'),
-      'type' => 'entity_reference_field',
-      'settings' => array('target_type' => 'comment'),
-    );
-    $properties['nid'] = array(
-      'label' => t('Node ID'),
-      'description' => t('The ID of the node of which this comment is a reply.'),
-      'type' => 'entity_reference_field',
-      'settings' => array('target_type' => 'node'),
-      'required' => TRUE,
-    );
-    $properties['langcode'] = array(
-      'label' => t('Language code'),
-      'description' => t('The comment language code.'),
-      'type' => 'language_field',
-    );
-    $properties['subject'] = array(
-      'label' => t('Subject'),
-      'description' => t('The comment title or subject.'),
-      'type' => 'string_field',
-    );
-    $properties['uid'] = array(
-      'label' => t('User ID'),
-      'description' => t('The user ID of the comment author.'),
-      'type' => 'entity_reference_field',
-      'settings' => array(
-        'target_type' => 'user',
-        'default_value' => 0,
-      ),
-    );
-    $properties['name'] = array(
-      'label' => t('Name'),
-      'description' => t("The comment author's name."),
-      'type' => 'string_field',
-      'settings' => array('default_value' => ''),
-    );
-    $properties['mail'] = array(
-      'label' => t('e-mail'),
-      'description' => t("The comment author's e-mail address."),
-      'type' => 'string_field',
-    );
-    $properties['homepage'] = array(
-      'label' => t('Homepage'),
-      'description' => t("The comment author's home page address."),
-      'type' => 'string_field',
-    );
-    $properties['hostname'] = array(
-      'label' => t('Hostname'),
-      'description' => t("The comment author's hostname."),
-      'type' => 'string_field',
-    );
-    $properties['created'] = array(
-      'label' => t('Created'),
-      'description' => t('The time that the comment was created.'),
-      'type' => 'integer_field',
-    );
-    $properties['changed'] = array(
-      'label' => t('Changed'),
-      'description' => t('The time that the comment was last edited.'),
-      'type' => 'integer_field',
-    );
-    $properties['status'] = array(
-      'label' => t('Publishing status'),
-      'description' => t('A boolean indicating whether the comment is published.'),
-      'type' => 'boolean_field',
-    );
-    $properties['thread'] = array(
-      'label' => t('Thread place'),
-      'description' => t("The alphadecimal representation of the comment's place in a thread, consisting of a base 36 string prefixed by an integer indicating its length."),
-      'type' => 'string_field',
-    );
-    $properties['node_type'] = array(
-      // @todo: The bundle property should be stored so it's queryable.
-      'label' => t('Node type'),
-      'description' => t("The comment node type."),
-      'type' => 'string_field',
-      'queryable' => FALSE,
-    );
-    $properties['new'] = array(
-      'label' => t('Comment new marker'),
-      'description' => t("The comment 'new' marker for the current user (0 read, 1 new, 2 updated)."),
-      'type' => 'integer_field',
-      'computed' => TRUE,
-      'class' => '\Drupal\comment\CommentNewItem',
-    );
-    return $properties;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function getMaxThread(EntityInterface $comment) {
     return db_query('SELECT MAX(thread) FROM {comment} WHERE nid = :nid', array(':nid' => $comment->nid->target_id))->fetchField();
   }
diff --git a/core/modules/comment/lib/Drupal/comment/Entity/Comment.php b/core/modules/comment/lib/Drupal/comment/Entity/Comment.php
index 4774ec5..0dcf37d 100644
--- a/core/modules/comment/lib/Drupal/comment/Entity/Comment.php
+++ b/core/modules/comment/lib/Drupal/comment/Entity/Comment.php
@@ -354,4 +354,109 @@ public function permalink() {
 
     return $url;
   }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function baseFieldDefinitions($entity_type) {
+    $properties['cid'] = array(
+      'label' => t('ID'),
+      'description' => t('The comment ID.'),
+      'type' => 'integer_field',
+      'read-only' => TRUE,
+    );
+    $properties['uuid'] = array(
+      'label' => t('UUID'),
+      'description' => t('The comment UUID.'),
+      'type' => 'uuid_field',
+    );
+    $properties['pid'] = array(
+      'label' => t('Parent ID'),
+      'description' => t('The parent comment ID if this is a reply to a comment.'),
+      'type' => 'entity_reference_field',
+      'settings' => array('target_type' => 'comment'),
+    );
+    $properties['nid'] = array(
+      'label' => t('Node ID'),
+      'description' => t('The ID of the node of which this comment is a reply.'),
+      'type' => 'entity_reference_field',
+      'settings' => array('target_type' => 'node'),
+      'required' => TRUE,
+    );
+    $properties['langcode'] = array(
+      'label' => t('Language code'),
+      'description' => t('The comment language code.'),
+      'type' => 'language_field',
+    );
+    $properties['subject'] = array(
+      'label' => t('Subject'),
+      'description' => t('The comment title or subject.'),
+      'type' => 'string_field',
+    );
+    $properties['uid'] = array(
+      'label' => t('User ID'),
+      'description' => t('The user ID of the comment author.'),
+      'type' => 'entity_reference_field',
+      'settings' => array(
+        'target_type' => 'user',
+        'default_value' => 0,
+      ),
+    );
+    $properties['name'] = array(
+      'label' => t('Name'),
+      'description' => t("The comment author's name."),
+      'type' => 'string_field',
+      'settings' => array('default_value' => ''),
+    );
+    $properties['mail'] = array(
+      'label' => t('e-mail'),
+      'description' => t("The comment author's e-mail address."),
+      'type' => 'string_field',
+    );
+    $properties['homepage'] = array(
+      'label' => t('Homepage'),
+      'description' => t("The comment author's home page address."),
+      'type' => 'string_field',
+    );
+    $properties['hostname'] = array(
+      'label' => t('Hostname'),
+      'description' => t("The comment author's hostname."),
+      'type' => 'string_field',
+    );
+    $properties['created'] = array(
+      'label' => t('Created'),
+      'description' => t('The time that the comment was created.'),
+      'type' => 'integer_field',
+    );
+    $properties['changed'] = array(
+      'label' => t('Changed'),
+      'description' => t('The time that the comment was last edited.'),
+      'type' => 'integer_field',
+    );
+    $properties['status'] = array(
+      'label' => t('Publishing status'),
+      'description' => t('A boolean indicating whether the comment is published.'),
+      'type' => 'boolean_field',
+    );
+    $properties['thread'] = array(
+      'label' => t('Thread place'),
+      'description' => t("The alphadecimal representation of the comment's place in a thread, consisting of a base 36 string prefixed by an integer indicating its length."),
+      'type' => 'string_field',
+    );
+    $properties['node_type'] = array(
+      // @todo: The bundle property should be stored so it's queryable.
+      'label' => t('Node type'),
+      'description' => t("The comment node type."),
+      'type' => 'string_field',
+      'queryable' => FALSE,
+    );
+    $properties['new'] = array(
+      'label' => t('Comment new marker'),
+      'description' => t("The comment 'new' marker for the current user (0 read, 1 new, 2 updated)."),
+      'type' => 'integer_field',
+      'computed' => TRUE,
+      'class' => '\Drupal\comment\CommentNewItem',
+    );
+    return $properties;
+  }
 }
diff --git a/core/modules/contact/lib/Drupal/contact/Entity/Message.php b/core/modules/contact/lib/Drupal/contact/Entity/Message.php
index 0c398d9..0c3c622 100644
--- a/core/modules/contact/lib/Drupal/contact/Entity/Message.php
+++ b/core/modules/contact/lib/Drupal/contact/Entity/Message.php
@@ -20,7 +20,7 @@
  *   label = @Translation("Contact message"),
  *   module = "contact",
  *   controllers = {
- *     "storage" = "Drupal\contact\MessageStorageController",
+ *     "storage" = "Drupal\Core\Entity\DatabaseStorageControllerNG",
  *     "render" = "Drupal\contact\MessageRenderController",
  *     "form" = {
  *       "default" = "Drupal\contact\MessageFormController"
@@ -138,4 +138,49 @@ public function getPersonalRecipient() {
     }
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public static function baseFieldDefinitions($entity_type) {
+    $fields['category'] = array(
+      'label' => t('Category ID'),
+      'description' => t('The ID of the associated category.'),
+      'type' => 'entity_reference_field',
+      'settings' => array('target_type' => 'contact_category'),
+      'required' => TRUE,
+    );
+    $fields['name'] = array(
+      'label' => t("The sender's name"),
+      'description' => t('The name of the person that is sending the contact message.'),
+      'type' => 'string_field',
+    );
+    $fields['mail'] = array(
+      'label' => t("The sender's e-mail"),
+      'description' => t('The e-mail of the person that is sending the contact message.'),
+      'type' => 'email_field',
+    );
+    $fields['subject'] = array(
+      'label' => t('The message subject'),
+      'description' => t('The subject of the contact message.'),
+      'type' => 'string_field',
+    );
+    $fields['message'] = array(
+      'label' => t('The message text'),
+      'description' => t('The text of the contact message.'),
+      'type' => 'string_field',
+    );
+    $fields['copy'] = array(
+      'label' => t('Copy'),
+      'description' => t('Whether to send a copy of the message to the sender.'),
+      'type' => 'boolean_field',
+    );
+    $fields['recipient'] = array(
+      'label' => t('Recipient ID'),
+      'description' => t('The ID of the recipient user for personal contact messages.'),
+      'type' => 'entity_reference_field',
+      'settings' => array('target_type' => 'user'),
+    );
+    return $fields;
+  }
+
 }
diff --git a/core/modules/contact/lib/Drupal/contact/MessageStorageController.php b/core/modules/contact/lib/Drupal/contact/MessageStorageController.php
deleted file mode 100644
index 71ad45a..0000000
--- a/core/modules/contact/lib/Drupal/contact/MessageStorageController.php
+++ /dev/null
@@ -1,61 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\contact\MessageStorageController.
- */
-
-namespace Drupal\contact;
-
-use Drupal\Core\Entity\DatabaseStorageControllerNG;
-
-/**
- * Defines the controller class for the contact message entity.
- */
-class MessageStorageController extends DatabaseStorageControllerNG {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function baseFieldDefinitions() {
-    $fields['category'] = array(
-      'label' => t('Category ID'),
-      'description' => t('The ID of the associated category.'),
-      'type' => 'entity_reference_field',
-      'settings' => array('target_type' => 'contact_category'),
-      'required' => TRUE,
-    );
-    $fields['name'] = array(
-      'label' => t("The sender's name"),
-      'description' => t('The name of the person that is sending the contact message.'),
-      'type' => 'string_field',
-    );
-    $fields['mail'] = array(
-      'label' => t("The sender's e-mail"),
-      'description' => t('The e-mail of the person that is sending the contact message.'),
-      'type' => 'email_field',
-    );
-    $fields['subject'] = array(
-      'label' => t('The message subject'),
-      'description' => t('The subject of the contact message.'),
-      'type' => 'string_field',
-    );
-    $fields['message'] = array(
-      'label' => t('The message text'),
-      'description' => t('The text of the contact message.'),
-      'type' => 'string_field',
-    );
-    $fields['copy'] = array(
-      'label' => t('Copy'),
-      'description' => t('Whether to send a copy of the message to the sender.'),
-      'type' => 'boolean_field',
-    );
-    $fields['recipient'] = array(
-      'label' => t('Recipient ID'),
-      'description' => t('The ID of the recipient user for personal contact messages.'),
-      'type' => 'entity_reference_field',
-      'settings' => array('target_type' => 'user'),
-    );
-    return $fields;
-  }
-}
diff --git a/core/modules/file/lib/Drupal/file/Entity/File.php b/core/modules/file/lib/Drupal/file/Entity/File.php
index dfe97cb..833f2db 100644
--- a/core/modules/file/lib/Drupal/file/Entity/File.php
+++ b/core/modules/file/lib/Drupal/file/Entity/File.php
@@ -208,4 +208,64 @@ public static function preDelete(EntityStorageControllerInterface $storage_contr
     }
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public static function baseFieldDefinitions($entity_type) {
+    $properties['fid'] = array(
+      'label' => t('File ID'),
+      'description' => t('The file ID.'),
+      'type' => 'integer_field',
+      'read-only' => TRUE,
+    );
+    $properties['uuid'] = array(
+      'label' => t('UUID'),
+      'description' => t('The file UUID.'),
+      'type' => 'uuid_field',
+      'read-only' => TRUE,
+    );
+    $properties['langcode'] = array(
+      'label' => t('Language code'),
+      'description' => t('The file language code.'),
+      'type' => 'language_field',
+    );
+    $properties['uid'] = array(
+      'label' => t('User ID'),
+      'description' => t('The user ID of the file.'),
+      'type' => 'entity_reference_field',
+      'settings' => array('target_type' => 'user'),
+    );
+    $properties['filename'] = array(
+      'label' => t('Filename'),
+      'description' => t('Name of the file with no path components.'),
+      'type' => 'string_field',
+    );
+    $properties['uri'] = array(
+      'label' => t('URI'),
+      'description' => t('The URI to access the file (either local or remote).'),
+      'type' => 'string_field',
+    );
+    $properties['filemime'] = array(
+      'label' => t('File MIME type'),
+      'description' => t("The file's MIME type."),
+      'type' => 'string_field',
+    );
+    $properties['filesize'] = array(
+      'label' => t('File size'),
+      'description' => t('The size of the file in bytes.'),
+      'type' => 'boolean_field',
+    );
+    $properties['status'] = array(
+      'label' => t('Status'),
+      'description' => t('The status of the file, temporary (0) and permanent (1)'),
+      'type' => 'integer_field',
+    );
+    $properties['timestamp'] = array(
+      'label' => t('Created'),
+      'description' => t('The time that the node was created.'),
+      'type' => 'integer_field',
+    );
+    return $properties;
+  }
+
 }
diff --git a/core/modules/file/lib/Drupal/file/FileStorageController.php b/core/modules/file/lib/Drupal/file/FileStorageController.php
index f3167a6..2f27551 100644
--- a/core/modules/file/lib/Drupal/file/FileStorageController.php
+++ b/core/modules/file/lib/Drupal/file/FileStorageController.php
@@ -38,64 +38,4 @@ public function retrieveTemporaryFiles() {
       ':timestamp' => REQUEST_TIME - DRUPAL_MAXIMUM_TEMP_FILE_AGE
     ));
   }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function baseFieldDefinitions() {
-    $properties['fid'] = array(
-      'label' => t('File ID'),
-      'description' => t('The file ID.'),
-      'type' => 'integer_field',
-      'read-only' => TRUE,
-    );
-    $properties['uuid'] = array(
-      'label' => t('UUID'),
-      'description' => t('The file UUID.'),
-      'type' => 'uuid_field',
-      'read-only' => TRUE,
-    );
-    $properties['langcode'] = array(
-      'label' => t('Language code'),
-      'description' => t('The file language code.'),
-      'type' => 'language_field',
-    );
-    $properties['uid'] = array(
-      'label' => t('User ID'),
-      'description' => t('The user ID of the file.'),
-      'type' => 'entity_reference_field',
-      'settings' => array('target_type' => 'user'),
-    );
-    $properties['filename'] = array(
-      'label' => t('Filename'),
-      'description' => t('Name of the file with no path components.'),
-      'type' => 'string_field',
-    );
-    $properties['uri'] = array(
-      'label' => t('URI'),
-      'description' => t('The URI to access the file (either local or remote).'),
-      'type' => 'string_field',
-    );
-    $properties['filemime'] = array(
-      'label' => t('File MIME type'),
-      'description' => t("The file's MIME type."),
-      'type' => 'string_field',
-    );
-    $properties['filesize'] = array(
-      'label' => t('File size'),
-      'description' => t('The size of the file in bytes.'),
-      'type' => 'boolean_field',
-    );
-    $properties['status'] = array(
-      'label' => t('Status'),
-      'description' => t('The status of the file, temporary (0) and permanent (1)'),
-      'type' => 'integer_field',
-    );
-    $properties['timestamp'] = array(
-      'label' => t('Created'),
-      'description' => t('The time that the node was created.'),
-      'type' => 'integer_field',
-    );
-    return $properties;
-  }
 }
diff --git a/core/modules/node/lib/Drupal/node/Entity/Node.php b/core/modules/node/lib/Drupal/node/Entity/Node.php
index 0452e99..ce28c4b 100644
--- a/core/modules/node/lib/Drupal/node/Entity/Node.php
+++ b/core/modules/node/lib/Drupal/node/Entity/Node.php
@@ -283,4 +283,122 @@ public function setRevisionAuthorId($uid) {
     return $this;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public static function baseFieldDefinitions($entity_type) {
+    $properties['nid'] = array(
+      'label' => t('Node ID'),
+      'description' => t('The node ID.'),
+      'type' => 'integer_field',
+      'read-only' => TRUE,
+    );
+    $properties['uuid'] = array(
+      'label' => t('UUID'),
+      'description' => t('The node UUID.'),
+      'type' => 'uuid_field',
+      'read-only' => TRUE,
+    );
+    $properties['vid'] = array(
+      'label' => t('Revision ID'),
+      'description' => t('The node revision ID.'),
+      'type' => 'integer_field',
+      'read-only' => TRUE,
+    );
+    $properties['type'] = array(
+      'label' => t('Type'),
+      'description' => t('The node type.'),
+      'type' => 'string_field',
+      'read-only' => TRUE,
+    );
+    $properties['langcode'] = array(
+      'label' => t('Language code'),
+      'description' => t('The node language code.'),
+      'type' => 'language_field',
+    );
+    $properties['title'] = array(
+      'label' => t('Title'),
+      'description' => t('The title of this node, always treated as non-markup plain text.'),
+      'type' => 'string_field',
+      'required' => TRUE,
+      'settings' => array(
+        'default_value' => '',
+      ),
+      'property_constraints' => array(
+        'value' => array('Length' => array('max' => 255)),
+      ),
+    );
+    $properties['uid'] = array(
+      'label' => t('User ID'),
+      'description' => t('The user ID of the node author.'),
+      'type' => 'entity_reference_field',
+      'settings' => array(
+        'target_type' => 'user',
+        'default_value' => 0,
+      ),
+    );
+    $properties['status'] = array(
+      'label' => t('Publishing status'),
+      'description' => t('A boolean indicating whether the node is published.'),
+      'type' => 'boolean_field',
+    );
+    $properties['created'] = array(
+      'label' => t('Created'),
+      'description' => t('The time that the node was created.'),
+      'type' => 'integer_field',
+    );
+    $properties['changed'] = array(
+      'label' => t('Changed'),
+      'description' => t('The time that the node was last edited.'),
+      'type' => 'integer_field',
+      'property_constraints' => array(
+        'value' => array('NodeChanged' => array()),
+      ),
+    );
+    $properties['comment'] = array(
+      'label' => t('Comment'),
+      'description' => t('Whether comments are allowed on this node: 0 = no, 1 = closed (read only), 2 = open (read/write).'),
+      'type' => 'integer_field',
+    );
+    $properties['promote'] = array(
+      'label' => t('Promote'),
+      'description' => t('A boolean indicating whether the node should be displayed on the front page.'),
+      'type' => 'boolean_field',
+    );
+    $properties['sticky'] = array(
+      'label' => t('Sticky'),
+      'description' => t('A boolean indicating whether the node should be displayed at the top of lists in which it appears.'),
+      'type' => 'boolean_field',
+    );
+    $properties['tnid'] = array(
+      'label' => t('Translation set ID'),
+      'description' => t('The translation set id for this node, which equals the node id of the source post in each set.'),
+      'type' => 'integer_field',
+    );
+    $properties['translate'] = array(
+      'label' => t('Translate'),
+      'description' => t('A boolean indicating whether this translation page needs to be updated.'),
+      'type' => 'boolean_field',
+    );
+    $properties['revision_timestamp'] = array(
+      'label' => t('Revision timestamp'),
+      'description' => t('The time that the current revision was created.'),
+      'type' => 'integer_field',
+      'queryable' => FALSE,
+    );
+    $properties['revision_uid'] = array(
+      'label' => t('Revision user ID'),
+      'description' => t('The user ID of the author of the current revision.'),
+      'type' => 'entity_reference_field',
+      'settings' => array('target_type' => 'user'),
+      'queryable' => FALSE,
+    );
+    $properties['log'] = array(
+      'label' => t('Log'),
+      'description' => t('The log entry explaining the changes in this version.'),
+      'type' => 'string_field',
+    );
+    return $properties;
+  }
+
 }
diff --git a/core/modules/node/lib/Drupal/node/NodeStorageController.php b/core/modules/node/lib/Drupal/node/NodeStorageController.php
index 1a874fe..88214f3 100644
--- a/core/modules/node/lib/Drupal/node/NodeStorageController.php
+++ b/core/modules/node/lib/Drupal/node/NodeStorageController.php
@@ -118,122 +118,4 @@ protected function postDelete($nodes) {
       ->execute();
   }
 
-  /**
-   * Overrides \Drupal\Core\Entity\DataBaseStorageControllerNG::basePropertyDefinitions().
-   */
-  public function baseFieldDefinitions() {
-    $properties['nid'] = array(
-      'label' => t('Node ID'),
-      'description' => t('The node ID.'),
-      'type' => 'integer_field',
-      'read-only' => TRUE,
-    );
-    $properties['uuid'] = array(
-      'label' => t('UUID'),
-      'description' => t('The node UUID.'),
-      'type' => 'uuid_field',
-      'read-only' => TRUE,
-    );
-    $properties['vid'] = array(
-      'label' => t('Revision ID'),
-      'description' => t('The node revision ID.'),
-      'type' => 'integer_field',
-      'read-only' => TRUE,
-    );
-    $properties['type'] = array(
-      'label' => t('Type'),
-      'description' => t('The node type.'),
-      'type' => 'string_field',
-      'read-only' => TRUE,
-    );
-    $properties['langcode'] = array(
-      'label' => t('Language code'),
-      'description' => t('The node language code.'),
-      'type' => 'language_field',
-    );
-    $properties['title'] = array(
-      'label' => t('Title'),
-      'description' => t('The title of this node, always treated as non-markup plain text.'),
-      'type' => 'string_field',
-      'required' => TRUE,
-      'settings' => array(
-        'default_value' => '',
-      ),
-      'property_constraints' => array(
-        'value' => array('Length' => array('max' => 255)),
-      ),
-    );
-    $properties['uid'] = array(
-      'label' => t('User ID'),
-      'description' => t('The user ID of the node author.'),
-      'type' => 'entity_reference_field',
-      'settings' => array(
-        'target_type' => 'user',
-        'default_value' => 0,
-      ),
-    );
-    $properties['status'] = array(
-      'label' => t('Publishing status'),
-      'description' => t('A boolean indicating whether the node is published.'),
-      'type' => 'boolean_field',
-    );
-    $properties['created'] = array(
-      'label' => t('Created'),
-      'description' => t('The time that the node was created.'),
-      'type' => 'integer_field',
-    );
-    $properties['changed'] = array(
-      'label' => t('Changed'),
-      'description' => t('The time that the node was last edited.'),
-      'type' => 'integer_field',
-      'property_constraints' => array(
-        'value' => array('NodeChanged' => array()),
-      ),
-    );
-    $properties['comment'] = array(
-      'label' => t('Comment'),
-      'description' => t('Whether comments are allowed on this node: 0 = no, 1 = closed (read only), 2 = open (read/write).'),
-      'type' => 'integer_field',
-    );
-    $properties['promote'] = array(
-      'label' => t('Promote'),
-      'description' => t('A boolean indicating whether the node should be displayed on the front page.'),
-      'type' => 'boolean_field',
-    );
-    $properties['sticky'] = array(
-      'label' => t('Sticky'),
-      'description' => t('A boolean indicating whether the node should be displayed at the top of lists in which it appears.'),
-      'type' => 'boolean_field',
-    );
-    $properties['tnid'] = array(
-      'label' => t('Translation set ID'),
-      'description' => t('The translation set id for this node, which equals the node id of the source post in each set.'),
-      'type' => 'integer_field',
-    );
-    $properties['translate'] = array(
-      'label' => t('Translate'),
-      'description' => t('A boolean indicating whether this translation page needs to be updated.'),
-      'type' => 'boolean_field',
-    );
-    $properties['revision_timestamp'] = array(
-      'label' => t('Revision timestamp'),
-      'description' => t('The time that the current revision was created.'),
-      'type' => 'integer_field',
-      'queryable' => FALSE,
-    );
-    $properties['revision_uid'] = array(
-      'label' => t('Revision user ID'),
-      'description' => t('The user ID of the author of the current revision.'),
-      'type' => 'entity_reference_field',
-      'settings' => array('target_type' => 'user'),
-      'queryable' => FALSE,
-    );
-    $properties['log'] = array(
-      'label' => t('Log'),
-      'description' => t('The log entry explaining the changes in this version.'),
-      'type' => 'string_field',
-    );
-    return $properties;
-  }
-
 }
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTest.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTest.php
index b7ddfe2..95d74ce 100644
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTest.php
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTest.php
@@ -101,4 +101,50 @@ public function label($langcode = Language::LANGCODE_DEFAULT) {
       return parent::label($langcode);
     }
   }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function baseFieldDefinitions($entity_type) {
+    $fields['id'] = array(
+      'label' => t('ID'),
+      'description' => t('The ID of the test entity.'),
+      'type' => 'integer_field',
+      'read-only' => TRUE,
+    );
+    $fields['uuid'] = array(
+      'label' => t('UUID'),
+      'description' => t('The UUID of the test entity.'),
+      'type' => 'uuid_field',
+    );
+    $fields['langcode'] = array(
+      'label' => t('Language code'),
+      'description' => t('The language code of the test entity.'),
+      'type' => 'language_field',
+    );
+    $fields['name'] = array(
+      'label' => t('Name'),
+      'description' => t('The name of the test entity.'),
+      'type' => 'string_field',
+      'translatable' => TRUE,
+      'property_constraints' => array(
+        'value' => array('Length' => array('max' => 32)),
+      ),
+    );
+    $fields['type'] = array(
+      'label' => t('Type'),
+      'description' => t('The bundle of the test entity.'),
+      'type' => 'string_field',
+      'required' => TRUE,
+      // @todo: Add allowed values validation.
+    );
+    $fields['user_id'] = array(
+      'label' => t('User ID'),
+      'description' => t('The ID of the associated user.'),
+      'type' => 'entity_reference_field',
+      'settings' => array('target_type' => 'user'),
+      'translatable' => TRUE,
+    );
+    return $fields;
+  }
 }
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestCache.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestCache.php
index 504bdc8..b4a064f 100644
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestCache.php
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestCache.php
@@ -7,7 +7,6 @@
 
 namespace Drupal\entity_test\Entity;
 
-use Drupal\Core\Entity\EntityNG;
 use Drupal\Core\Entity\Annotation\EntityType;
 use Drupal\Core\Annotation\Translation;
 use Drupal\Core\Language\Language;
@@ -38,7 +37,7 @@
  *   menu_base_path = "entity-test/manage/%entity_test"
  * )
  */
-class EntityTestCache extends EntityNG {
+class EntityTestCache extends EntityTest {
 
   /**
    * The entity ID.
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestMul.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestMul.php
index 2da7b65..3f7e833 100644
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestMul.php
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestMul.php
@@ -19,7 +19,7 @@
  *   label = @Translation("Test entity - data table"),
  *   module = "entity_test",
  *   controllers = {
- *     "storage" = "Drupal\entity_test\EntityTestMulStorageController",
+ *     "storage" = "Drupal\entity_test\EntityTestStorageController",
  *     "access" = "Drupal\entity_test\EntityTestAccessController",
  *     "form" = {
  *       "default" = "Drupal\entity_test\EntityTestFormController"
@@ -40,4 +40,17 @@
  */
 class EntityTestMul extends EntityTest {
 
+  /**
+   * {@inheritdoc}
+   */
+  public static function baseFieldDefinitions($entity_type) {
+    $fields = parent::baseFieldDefinitions($entity_type);
+    $fields['default_langcode'] = array(
+      'label' => t('Default language'),
+      'description' => t('Flag to indicate whether this is the default language.'),
+      'type' => 'boolean_field',
+    );
+    return $fields;
+  }
+
 }
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestMulRev.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestMulRev.php
index 5ad480a..4a578e2 100644
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestMulRev.php
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestMulRev.php
@@ -19,7 +19,7 @@
  *   label = @Translation("Test entity - revisions and data table"),
  *   module = "entity_test",
  *   controllers = {
- *     "storage" = "Drupal\entity_test\EntityTestMulRevStorageController",
+ *     "storage" = "Drupal\entity_test\EntityTestStorageController",
  *     "access" = "Drupal\entity_test\EntityTestAccessController",
  *     "form" = {
  *       "default" = "Drupal\entity_test\EntityTestFormController"
@@ -42,4 +42,23 @@
  */
 class EntityTestMulRev extends EntityTestRev {
 
+  /**
+   * {@inheritdoc}
+   */
+  public static function baseFieldDefinitions($entity_type) {
+    $fields = parent::baseFieldDefinitions($entity_type);
+    $fields['revision_id'] = array(
+      'label' => t('ID'),
+      'description' => t('The version id of the test entity.'),
+      'type' => 'integer_field',
+      'read-only' => TRUE,
+    );
+    $fields['default_langcode'] = array(
+      'label' => t('Default language'),
+      'description' => t('Flag to inditcate whether this is the default language.'),
+      'type' => 'boolean_field',
+    );
+    return $fields;
+  }
+
 }
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestRev.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestRev.php
index cec6c2a..0fabcca 100644
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestRev.php
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestRev.php
@@ -19,7 +19,7 @@
  *   label = @Translation("Test entity - revisions"),
  *   module = "entity_test",
  *   controllers = {
- *     "storage" = "Drupal\entity_test\EntityTestRevStorageController",
+ *     "storage" = "Drupal\entity_test\EntityTestStorageController",
  *     "access" = "Drupal\entity_test\EntityTestAccessController",
  *     "form" = {
  *       "default" = "Drupal\entity_test\EntityTestFormController"
@@ -61,4 +61,18 @@ public function init() {
   public function getRevisionId() {
     return $this->get('revision_id')->value;
   }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function baseFieldDefinitions($entity_type) {
+    $fields = parent::baseFieldDefinitions($entity_type);
+    $fields['revision_id'] = array(
+      'label' => t('ID'),
+      'description' => t('The version id of the test entity.'),
+      'type' => 'integer_field',
+      'read-only' => TRUE,
+    );
+    return $fields;
+  }
 }
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestMulRevStorageController.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestMulRevStorageController.php
deleted file mode 100644
index f940ed0..0000000
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestMulRevStorageController.php
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-
-/**
- * @file
- * Definition of Drupal\entity_test\EntityTestMulRevStorageController.
- */
-
-namespace Drupal\entity_test;
-
-use Drupal\entity_test\EntityTestStorageController;
-
-/**
- * Defines the controller class for the test entity.
- *
- * This extends the Drupal\entity_test\EntityTestStorageController class, adding
- * required special handling for test entities with multilingual property and
- * revision support.
- */
-class EntityTestMulRevStorageController extends EntityTestStorageController {
-
-  /**
-   * Overrides \Drupal\entity_test\EntityTestStorageController::baseFieldDefinitions().
-   */
-  public function baseFieldDefinitions() {
-    $fields = parent::baseFieldDefinitions();
-    $fields['revision_id'] = array(
-      'label' => t('ID'),
-      'description' => t('The version id of the test entity.'),
-      'type' => 'integer_field',
-      'read-only' => TRUE,
-    );
-    $fields['default_langcode'] = array(
-      'label' => t('Default language'),
-      'description' => t('Flag to inditcate whether this is the default language.'),
-      'type' => 'boolean_field',
-    );
-    return $fields;
-  }
-}
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestMulStorageController.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestMulStorageController.php
deleted file mode 100644
index 786e91a..0000000
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestMulStorageController.php
+++ /dev/null
@@ -1,33 +0,0 @@
-<?php
-
-/**
- * @file
- * Definition of Drupal\entity_test\EntityTestMulStorageController.
- */
-
-namespace Drupal\entity_test;
-
-use Drupal\entity_test\EntityTestStorageController;
-
-/**
- * Defines the controller class for the test entity.
- *
- * This extends the Drupal\entity_test\EntityTestStorageController class, adding
- * required special handling for test entities with multilingual property
- * support.
- */
-class EntityTestMulStorageController extends EntityTestStorageController {
-
-  /**
-   * Overrides \Drupal\entity_test\EntityTestStorageController::baseFieldDefinitions().
-   */
-  public function baseFieldDefinitions() {
-    $fields = parent::baseFieldDefinitions();
-    $fields['default_langcode'] = array(
-      'label' => t('Default language'),
-      'description' => t('Flag to indicate whether this is the default language.'),
-      'type' => 'boolean_field',
-    );
-    return $fields;
-  }
-}
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestRevStorageController.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestRevStorageController.php
deleted file mode 100644
index 0fec01e..0000000
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestRevStorageController.php
+++ /dev/null
@@ -1,33 +0,0 @@
-<?php
-
-/**
- * @file
- * Definition of Drupal\entity_test\EntityTestRevStorageController.
- */
-
-namespace Drupal\entity_test;
-
-use Drupal\entity_test\EntityTestStorageController;
-
-/**
- * Defines the controller class for the test entity.
- *
- * This extends the Drupal\entity_test\EntityTestStorageController class, adding
- * required special handling for test entities with revision support.
- */
-class EntityTestRevStorageController extends EntityTestStorageController {
-
-  /**
-   * Overrides \Drupal\entity_test\EntityTestStorageController::baseFieldDefinitions().
-   */
-  public function baseFieldDefinitions() {
-    $fields = parent::baseFieldDefinitions();
-    $fields['revision_id'] = array(
-      'label' => t('ID'),
-      'description' => t('The version id of the test entity.'),
-      'type' => 'integer_field',
-      'read-only' => TRUE,
-    );
-    return $fields;
-  }
-}
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestStorageController.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestStorageController.php
index be93b68..bb8d390 100644
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestStorageController.php
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestStorageController.php
@@ -27,49 +27,4 @@ public function create(array $values) {
     return parent::create($values);
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function baseFieldDefinitions() {
-    $fields['id'] = array(
-      'label' => t('ID'),
-      'description' => t('The ID of the test entity.'),
-      'type' => 'integer_field',
-      'read-only' => TRUE,
-    );
-    $fields['uuid'] = array(
-      'label' => t('UUID'),
-      'description' => t('The UUID of the test entity.'),
-      'type' => 'uuid_field',
-    );
-    $fields['langcode'] = array(
-      'label' => t('Language code'),
-      'description' => t('The language code of the test entity.'),
-      'type' => 'language_field',
-    );
-    $fields['name'] = array(
-      'label' => t('Name'),
-      'description' => t('The name of the test entity.'),
-      'type' => 'string_field',
-      'translatable' => TRUE,
-      'property_constraints' => array(
-        'value' => array('Length' => array('max' => 32)),
-      ),
-    );
-    $fields['type'] = array(
-      'label' => t('Type'),
-      'description' => t('The bundle of the test entity.'),
-      'type' => 'string_field',
-      'required' => TRUE,
-      // @todo: Add allowed values validation.
-    );
-    $fields['user_id'] = array(
-      'label' => t('User ID'),
-      'description' => t('The ID of the associated user.'),
-      'type' => 'entity_reference_field',
-      'settings' => array('target_type' => 'user'),
-      'translatable' => TRUE,
-    );
-    return $fields;
-  }
 }
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Entity/Term.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Entity/Term.php
index 9dd69d7..daeb3ac 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Entity/Term.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Entity/Term.php
@@ -185,4 +185,63 @@ public function postSave(EntityStorageControllerInterface $storage_controller, $
     }
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public static function baseFieldDefinitions($entity_type) {
+    $properties['tid'] = array(
+      'label' => t('Term ID'),
+      'description' => t('The term ID.'),
+      'type' => 'integer_field',
+      'read-only' => TRUE,
+    );
+    $properties['uuid'] = array(
+      'label' => t('UUID'),
+      'description' => t('The term UUID.'),
+      'type' => 'uuid_field',
+      'read-only' => TRUE,
+    );
+    $properties['vid'] = array(
+      'label' => t('Vocabulary ID'),
+      'description' => t('The ID of the vocabulary to which the term is assigned.'),
+      'type' => 'string_field',
+    );
+    $properties['langcode'] = array(
+      'label' => t('Language code'),
+      'description' => t('The term language code.'),
+      'type' => 'language_field',
+    );
+    $properties['name'] = array(
+      'label' => t('Name'),
+      'description' => t('The term name.'),
+      'type' => 'string_field',
+    );
+    $properties['description'] = array(
+      'label' => t('Description'),
+      'description' => t('A description of the term'),
+      'type' => 'string_field',
+    );
+    // @todo Combine with description.
+    $properties['format'] = array(
+      'label' => t('Description format'),
+      'description' => t('The filter format ID of the description.'),
+      'type' => 'string_field',
+    );
+    $properties['weight'] = array(
+      'label' => t('Weight'),
+      'description' => t('The weight of this term in relation to other terms.'),
+      'type' => 'integer_field',
+      'settings' => array('default_value' => 0),
+    );
+    $properties['parent'] = array(
+      'label' => t('Term Parents'),
+      'description' => t('The parents of this term.'),
+      'type' => 'integer_field',
+      // Save new terms with no parents by default.
+      'settings' => array('default_value' => 0),
+      'computed' => TRUE,
+    );
+    return $properties;
+  }
+
 }
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/TermStorageController.php b/core/modules/taxonomy/lib/Drupal/taxonomy/TermStorageController.php
index cb0821c..f77b1b5 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/TermStorageController.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/TermStorageController.php
@@ -58,65 +58,6 @@ public function resetCache(array $ids = NULL) {
   }
 
   /**
-   * Overrides \Drupal\Core\Entity\DatabaseStorageControllerNG::baseFieldDefintions().
-   */
-  public function baseFieldDefinitions() {
-    $properties['tid'] = array(
-      'label' => t('Term ID'),
-      'description' => t('The term ID.'),
-      'type' => 'integer_field',
-      'read-only' => TRUE,
-    );
-    $properties['uuid'] = array(
-      'label' => t('UUID'),
-      'description' => t('The term UUID.'),
-      'type' => 'uuid_field',
-      'read-only' => TRUE,
-    );
-    $properties['vid'] = array(
-      'label' => t('Vocabulary ID'),
-      'description' => t('The ID of the vocabulary to which the term is assigned.'),
-      'type' => 'string_field',
-    );
-    $properties['langcode'] = array(
-      'label' => t('Language code'),
-      'description' => t('The term language code.'),
-      'type' => 'language_field',
-    );
-    $properties['name'] = array(
-      'label' => t('Name'),
-      'description' => t('The term name.'),
-      'type' => 'string_field',
-    );
-    $properties['description'] = array(
-      'label' => t('Description'),
-      'description' => t('A description of the term'),
-      'type' => 'string_field',
-    );
-    // @todo Combine with description.
-    $properties['format'] = array(
-      'label' => t('Description format'),
-      'description' => t('The filter format ID of the description.'),
-      'type' => 'string_field',
-    );
-    $properties['weight'] = array(
-      'label' => t('Weight'),
-      'description' => t('The weight of this term in relation to other terms.'),
-      'type' => 'integer_field',
-      'settings' => array('default_value' => 0),
-    );
-    $properties['parent'] = array(
-      'label' => t('Term Parents'),
-      'description' => t('The parents of this term.'),
-      'type' => 'integer_field',
-      // Save new terms with no parents by default.
-      'settings' => array('default_value' => 0),
-      'computed' => TRUE,
-    );
-    return $properties;
-  }
-
-  /**
    * {@inheritdoc}
    */
   public function deleteTermHierarchy($tids) {
diff --git a/core/modules/user/lib/Drupal/user/Entity/User.php b/core/modules/user/lib/Drupal/user/Entity/User.php
index 4e87d15..3f1a54f 100644
--- a/core/modules/user/lib/Drupal/user/Entity/User.php
+++ b/core/modules/user/lib/Drupal/user/Entity/User.php
@@ -410,4 +410,109 @@ public function setUsername($username) {
     return $this;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public static function baseFieldDefinitions($entity_type) {
+    $properties['uid'] = array(
+      'label' => t('User ID'),
+      'description' => t('The user ID.'),
+      'type' => 'integer_field',
+      'read-only' => TRUE,
+    );
+    $properties['uuid'] = array(
+      'label' => t('UUID'),
+      'description' => t('The user UUID.'),
+      'type' => 'uuid_field',
+      'read-only' => TRUE,
+    );
+    $properties['langcode'] = array(
+      'label' => t('Language code'),
+      'description' => t('The user language code.'),
+      'type' => 'language_field',
+    );
+    $properties['preferred_langcode'] = array(
+      'label' => t('Language code'),
+      'description' => t("The user's preferred langcode for receiving emails and viewing the site."),
+      'type' => 'language_field',
+    );
+    $properties['preferred_admin_langcode'] = array(
+      'label' => t('Language code'),
+      'description' => t("The user's preferred langcode for viewing administration pages."),
+      'type' => 'language_field',
+    );
+    $properties['name'] = array(
+      'label' => t('Name'),
+      'description' => t('The name of this user'),
+      'type' => 'string_field',
+      'settings' => array('default_value' => ''),
+    );
+    $properties['pass'] = array(
+      'label' => t('Name'),
+      'description' => t('The password of this user (hashed)'),
+      'type' => 'string_field',
+    );
+    $properties['mail'] = array(
+      'label' => t('Name'),
+      'description' => t('The e-mail of this user'),
+      'type' => 'string_field',
+      'settings' => array('default_value' => ''),
+    );
+    $properties['signature'] = array(
+      'label' => t('Name'),
+      'description' => t('The signature of this user'),
+      'type' => 'string_field',
+    );
+    $properties['signature_format'] = array(
+      'label' => t('Name'),
+      'description' => t('The signature format of this user'),
+      'type' => 'string_field',
+    );
+    $properties['theme'] = array(
+      'label' => t('Theme'),
+      'description' => t('The default theme of this user'),
+      'type' => 'string_field',
+    );
+    $properties['timezone'] = array(
+      'label' => t('Timezone'),
+      'description' => t('The timezone of this user'),
+      'type' => 'string_field',
+    );
+    $properties['status'] = array(
+      'label' => t('User status'),
+      'description' => t('Whether the user is active (1) or blocked (0).'),
+      'type' => 'boolean_field',
+      'settings' => array('default_value' => 1),
+    );
+    $properties['created'] = array(
+      'label' => t('Created'),
+      'description' => t('The time that the node was created.'),
+      'type' => 'integer_field',
+    );
+    $properties['access'] = array(
+      'label' => t('Last access'),
+      'description' => t('The time that the user last accessed the site.'),
+      'type' => 'integer_field',
+      'settings' => array('default_value' => 0),
+    );
+    $properties['login'] = array(
+      'label' => t('Last login'),
+      'description' => t('The time that the user last logged in.'),
+      'type' => 'integer_field',
+      'settings' => array('default_value' => 0),
+    );
+    $properties['init'] = array(
+      'label' => t('Init'),
+      'description' => t('The email address used for initial account creation.'),
+      'type' => 'string_field',
+      'settings' => array('default_value' => ''),
+    );
+    $properties['roles'] = array(
+      'label' => t('Roles'),
+      'description' => t('The roles the user has.'),
+      'type' => 'string_field',
+    );
+    return $properties;
+  }
+
 }
diff --git a/core/modules/user/lib/Drupal/user/UserStorageController.php b/core/modules/user/lib/Drupal/user/UserStorageController.php
index a441023..efa8924 100644
--- a/core/modules/user/lib/Drupal/user/UserStorageController.php
+++ b/core/modules/user/lib/Drupal/user/UserStorageController.php
@@ -158,109 +158,4 @@ protected function invokeHook($hook, EntityInterface $entity) {
     // Invoke the respective entity-level hook.
     \Drupal::moduleHandler()->invokeAll('entity_' . $hook, array($entity, $this->entityType));
   }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function baseFieldDefinitions() {
-    $properties['uid'] = array(
-      'label' => t('User ID'),
-      'description' => t('The user ID.'),
-      'type' => 'integer_field',
-      'read-only' => TRUE,
-    );
-    $properties['uuid'] = array(
-      'label' => t('UUID'),
-      'description' => t('The user UUID.'),
-      'type' => 'uuid_field',
-      'read-only' => TRUE,
-    );
-    $properties['langcode'] = array(
-      'label' => t('Language code'),
-      'description' => t('The user language code.'),
-      'type' => 'language_field',
-    );
-    $properties['preferred_langcode'] = array(
-      'label' => t('Language code'),
-      'description' => t("The user's preferred langcode for receiving emails and viewing the site."),
-      'type' => 'language_field',
-    );
-    $properties['preferred_admin_langcode'] = array(
-      'label' => t('Language code'),
-      'description' => t("The user's preferred langcode for viewing administration pages."),
-      'type' => 'language_field',
-    );
-    $properties['name'] = array(
-      'label' => t('Name'),
-      'description' => t('The name of this user'),
-      'type' => 'string_field',
-      'settings' => array('default_value' => ''),
-    );
-    $properties['pass'] = array(
-      'label' => t('Name'),
-      'description' => t('The password of this user (hashed)'),
-      'type' => 'string_field',
-    );
-    $properties['mail'] = array(
-      'label' => t('Name'),
-      'description' => t('The e-mail of this user'),
-      'type' => 'string_field',
-      'settings' => array('default_value' => ''),
-    );
-    $properties['signature'] = array(
-      'label' => t('Name'),
-      'description' => t('The signature of this user'),
-      'type' => 'string_field',
-    );
-    $properties['signature_format'] = array(
-      'label' => t('Name'),
-      'description' => t('The signature format of this user'),
-      'type' => 'string_field',
-    );
-    $properties['theme'] = array(
-      'label' => t('Theme'),
-      'description' => t('The default theme of this user'),
-      'type' => 'string_field',
-    );
-    $properties['timezone'] = array(
-      'label' => t('Timezone'),
-      'description' => t('The timezone of this user'),
-      'type' => 'string_field',
-    );
-    $properties['status'] = array(
-      'label' => t('User status'),
-      'description' => t('Whether the user is active (1) or blocked (0).'),
-      'type' => 'boolean_field',
-      'settings' => array('default_value' => 1),
-    );
-    $properties['created'] = array(
-      'label' => t('Created'),
-      'description' => t('The time that the node was created.'),
-      'type' => 'integer_field',
-    );
-    $properties['access'] = array(
-      'label' => t('Last access'),
-      'description' => t('The time that the user last accessed the site.'),
-      'type' => 'integer_field',
-      'settings' => array('default_value' => 0),
-    );
-    $properties['login'] = array(
-      'label' => t('Last login'),
-      'description' => t('The time that the user last logged in.'),
-      'type' => 'integer_field',
-      'settings' => array('default_value' => 0),
-    );
-    $properties['init'] = array(
-      'label' => t('Init'),
-      'description' => t('The email address used for initial account creation.'),
-      'type' => 'string_field',
-      'settings' => array('default_value' => ''),
-    );
-    $properties['roles'] = array(
-      'label' => t('Roles'),
-      'description' => t('The roles the user has.'),
-      'type' => 'string_field',
-    );
-    return $properties;
-  }
 }
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/ViewUI.php b/core/modules/views_ui/lib/Drupal/views_ui/ViewUI.php
index 33b81a6..c7ac8a2 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/ViewUI.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/ViewUI.php
@@ -1236,4 +1236,14 @@ public function mergeDefaultDisplaysOptions() {
   public function uriRelationships() {
     return $this->storage->uriRelationships();
   }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function baseFieldDefinitions($entity_type) {
+    // @todo: This class is not directly defined as an entity type and does
+    //   not have base definitions but has to implement this method. Remove in
+    //   http://drupal.org/node/2024963.
+    return array();
+  }
 }
