diff --git a/core/includes/entity.api.php b/core/includes/entity.api.php
index 8e60f00..2b43a6c 100644
--- a/core/includes/entity.api.php
+++ b/core/includes/entity.api.php
@@ -171,9 +171,7 @@ function hook_entity_info_alter(&$entity_info) {
  *   The entity object.
  */
 function hook_entity_create(\Drupal\Core\Entity\EntityInterface $entity) {
-  // @todo Remove the check for EntityNG once all entity types have been
-  //   converted to it.
-  if (!isset($entity->foo) && ($entity instanceof \Drupal\Core\Entity\EntityNG)) {
+  if ($entity instanceof \Drupal\Core\Entity\ContentEntityBase && !$entity->foo->value) {
     $entity->foo->value = 'some_initial_value';
   }
 }
diff --git a/core/lib/Drupal/Core/Entity/EntityNG.php b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
similarity index 87%
rename from core/lib/Drupal/Core/Entity/EntityNG.php
rename to core/lib/Drupal/Core/Entity/ContentEntityBase.php
index ac975d1..ad975d5 100644
--- a/core/lib/Drupal/Core/Entity/EntityNG.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Contains \Drupal\Core\Entity\EntityNG.
+ * Contains \Drupal\Core\Entity\ContentEntityBase.
  */
 
 namespace Drupal\Core\Entity;
@@ -10,7 +10,6 @@
 use Drupal\Core\Language\Language;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\TypedData\TypedDataInterface;
-use ArrayIterator;
 use InvalidArgumentException;
 
 /**
@@ -24,7 +23,7 @@
  * @todo: Once all entity types have been converted, merge improvements into the
  * Entity class and overhaul the EntityInterface.
  */
-class EntityNG extends Entity {
+abstract class ContentEntityBase extends Entity implements \IteratorAggregate, ContentEntityInterface {
 
   /**
    * Status code indentifying a removed translation.
@@ -93,7 +92,7 @@ class EntityNG extends Entity {
   /**
    * Local cache for field definitions.
    *
-   * @see EntityNG::getPropertyDefinitions()
+   * @see ContentEntityBase::getPropertyDefinitions()
    *
    * @var array
    */
@@ -135,6 +134,20 @@ class EntityNG extends Entity {
   protected $translationInitialize = FALSE;
 
   /**
+   * Boolean indicating whether a new revision should be created on save.
+   *
+   * @var bool
+   */
+  protected $newRevision = FALSE;
+
+  /**
+   * Indicates whether this is the default revision.
+   *
+   * @var bool
+   */
+  protected $isDefaultRevision = TRUE;
+
+  /**
    * Overrides Entity::__construct().
    */
   public function __construct(array $values, $entity_type, $bundle = FALSE, $translations = array()) {
@@ -168,6 +181,142 @@ public function __construct(array $values, $entity_type, $bundle = FALSE, $trans
   }
 
   /**
+   * {@inheritdoc}
+   */
+  public function setNewRevision($value = TRUE) {
+    $this->newRevision = $value;
+  }
+  /**
+   * {@inheritdoc}
+   */
+  public function isNewRevision() {
+    $info = $this->entityInfo();
+    return $this->newRevision || (!empty($info['entity_keys']['revision']) && !$this->getRevisionId());
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getRevisionId() {
+    return NULL;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isTranslatable() {
+    // @todo Inject the entity manager and retrieve bundle info from it.
+    $bundles = entity_get_bundles($this->entityType);
+    return !empty($bundles[$this->bundle()]['translatable']);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function preSaveRevision(EntityStorageControllerInterface $storage_controller, \stdClass $record) {
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDefinition() {
+    // @todo: This does not make much sense, so remove once TypedDataInterface
+    // is removed. See https://drupal.org/node/2002138.
+    if ($this->bundle() != $this->entityType()) {
+      $type = 'entity:' . $this->entityType() . ':' . $this->bundle();
+    }
+    else {
+      $type = 'entity:' . $this->entityType();
+    }
+    return array('type' => $type);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getValue() {
+    // @todo: This does not make much sense, so remove once TypedDataInterface
+    // is removed. See https://drupal.org/node/2002138.
+    return $this->getPropertyValues();
+  }
+
+  /**
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::setValue().
+   */
+  public function setValue($value, $notify = TRUE) {
+    // @todo: This does not make much sense, so remove once TypedDataInterface
+    // is removed. See https://drupal.org/node/2002138.
+    $this->setPropertyValues($value);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getString() {
+    return $this->label();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validate() {
+    // @todo: Add the typed data manager as proper dependency.
+    return \Drupal::typedData()->getValidator()->validate($this);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function applyDefaultValue($notify = TRUE) {
+    foreach ($this->getProperties() as $property) {
+      $property->applyDefaultValue(FALSE);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getConstraints() {
+    return array();
+  }
+
+  /**
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::getName().
+   */
+  public function getName() {
+    return NULL;
+  }
+
+  /**
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::getRoot().
+   */
+  public function getRoot() {
+    return $this;
+  }
+
+  /**
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::getPropertyPath().
+   */
+  public function getPropertyPath() {
+    return '';
+  }
+
+  /**
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::getParent().
+   */
+  public function getParent() {
+    return NULL;
+  }
+
+  /**
+   * Implements \Drupal\Core\TypedData\TypedDataInterface::setContext().
+   */
+  public function setContext($name = NULL, TypedDataInterface $parent = NULL) {
+    // As entities are always the root of the tree of typed data, we do not need
+    // to set any parent or name.
+  }
+
+  /**
    * Initialize the object. Invoked upon construction and wake up.
    */
   protected function init() {
@@ -345,7 +494,7 @@ public function getProperties($include_computed = FALSE) {
    * Implements \IteratorAggregate::getIterator().
    */
   public function getIterator() {
-    return new ArrayIterator($this->getProperties());
+    return new \ArrayIterator($this->getProperties());
   }
 
   /**
@@ -446,7 +595,7 @@ public function language() {
    */
   protected function getDefaultLanguage() {
     // Keep a local cache of the language object and clear it if the langcode
-    // gets changed, see EntityNG::onChange().
+    // gets changed, see ContentEntityBase::onChange().
     if (!isset($this->language)) {
       // Get the language code if the property exists.
       if ($this->getPropertyDefinition('langcode') && ($item = $this->get('langcode')) && isset($item->language)) {
diff --git a/core/lib/Drupal/Core/Entity/EntityNGConfirmFormBase.php b/core/lib/Drupal/Core/Entity/ContentEntityConfirmFormBase.php
similarity index 93%
rename from core/lib/Drupal/Core/Entity/EntityNGConfirmFormBase.php
rename to core/lib/Drupal/Core/Entity/ContentEntityConfirmFormBase.php
index 742e379..f987bf2 100644
--- a/core/lib/Drupal/Core/Entity/EntityNGConfirmFormBase.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityConfirmFormBase.php
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Contains \Drupal\Core\Entity\EntityNGConfirmFormBase.
+ * Contains \Drupal\Core\Entity\ContentEntityConfirmFormBase.
  */
 
 namespace Drupal\Core\Entity;
@@ -13,7 +13,7 @@
 /**
  * Provides a generic base class for an entity-based confirmation form.
  */
-abstract class EntityNGConfirmFormBase extends EntityFormControllerNG implements ConfirmFormInterface {
+abstract class ContentEntityConfirmFormBase extends ContentEntityFormController implements ConfirmFormInterface {
 
   /**
    * {@inheritdoc}
diff --git a/core/lib/Drupal/Core/Entity/ContentEntityFormController.php b/core/lib/Drupal/Core/Entity/ContentEntityFormController.php
new file mode 100644
index 0000000..a987744
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/ContentEntityFormController.php
@@ -0,0 +1,162 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\EntityFormControllerNG.
+ */
+
+namespace Drupal\Core\Entity;
+
+use Drupal\Core\Language\Language;
+
+/**
+ * Entity form controller variant for content entity types.
+ *
+ * @see \Drupal\Core\ContentEntityBase
+ */
+class ContentEntityFormController extends EntityFormController {
+
+  /**
+   * Overrides EntityFormController::form().
+   */
+  public function form(array $form, array &$form_state) {
+    $entity = $this->entity;
+    // @todo Exploit the Field API to generate the default widgets for the
+    // entity fields.
+    $info = $entity->entityInfo();
+    if (!empty($info['fieldable'])) {
+      field_attach_form($entity, $form, $form_state, $this->getFormLangcode($form_state));
+    }
+
+    // Add a process callback so we can assign weights and hide extra fields.
+    $form['#process'][] = array($this, 'processForm');
+
+    return $form;
+  }
+
+  /**
+   * Implements \Drupal\Core\Entity\EntityFormControllerInterface::validate().
+   */
+  public function validate(array $form, array &$form_state) {
+    $entity = $this->buildEntity($form, $form_state);
+    $entity_type = $entity->entityType();
+    $entity_langcode = $entity->language()->id;
+
+    $violations = array();
+    foreach ($entity as $field_name => $field) {
+      $field_violations = $field->validate();
+      if (count($field_violations)) {
+        $violations[$field_name] = $field_violations;
+      }
+    }
+
+    // Map errors back to form elements.
+    if ($violations) {
+      foreach ($violations as $field_name => $field_violations) {
+        $langcode = field_is_translatable($entity_type, field_info_field($entity_type, $field_name)) ? $entity_langcode : Language::LANGCODE_NOT_SPECIFIED;
+        $field_state = field_form_get_state($form['#parents'], $field_name, $langcode, $form_state);
+        $field_state['constraint_violations'] = $field_violations;
+        field_form_set_state($form['#parents'], $field_name, $langcode, $form_state, $field_state);
+      }
+
+      field_invoke_method('flagErrors', _field_invoke_widget_target($form_state['form_display']), $entity, $form, $form_state);
+    }
+
+    // @todo Remove this.
+    // Execute legacy global validation handlers.
+    unset($form_state['validate_handlers']);
+    form_execute_handlers('validate', $form, $form_state);
+  }
+
+  /**
+   * Initialize the form state and the entity before the first form build.
+   */
+  protected function init(array &$form_state) {
+    // Ensure we act on the translation object corresponding to the current form
+    // language.
+    $this->entity = $this->getTranslatedEntity($form_state);
+    parent::init($form_state);
+  }
+
+  /**
+   * Returns the translation object corresponding to the form language.
+   *
+   * @param array $form_state
+   *   A keyed array containing the current state of the form.
+   */
+  protected function getTranslatedEntity(array $form_state) {
+    $langcode = $this->getFormLangcode($form_state);
+    $translation = $this->entity->getTranslation($langcode);
+    // Ensure that the entity object is a BC entity if the original one is.
+    return $this->entity instanceof EntityBCDecorator ? $translation->getBCEntity() : $translation;
+  }
+
+  /**
+   * Implements \Drupal\Core\Entity\EntityFormControllerInterface::getFormLangcode().
+   */
+  public function getFormLangcode(array $form_state) {
+    $entity = $this->entity;
+    // If no form langcode was provided we default to the current content
+    // language and inspect existing translations to find a valid fallback,
+    // if any.
+    $translations = $entity->getTranslationLanguages();
+    $languageManager = \Drupal::languageManager();
+    $langcode = $languageManager->getLanguage(Language::TYPE_CONTENT)->id;
+    $fallback = $languageManager->isMultilingual() ? language_fallback_get_candidates() : array();
+    while (!empty($langcode) && !isset($translations[$langcode])) {
+      $langcode = array_shift($fallback);
+    }
+
+    // If the site is not multilingual or no translation for the given form
+    // language is available, fall back to the entity language.
+    if (!empty($langcode))  {
+      return $langcode;
+    }
+    else {
+      // If the entity is translatable, return the original language.
+      return $entity->getUntranslated()->language()->id;
+    }
+  }
+
+  /**
+   * Implements \Drupal\Core\Entity\EntityFormControllerInterface::isDefaultFormLangcode().
+   */
+  public function isDefaultFormLangcode(array $form_state) {
+    return $this->getFormLangcode($form_state) == $this->entity->getUntranslated()->language()->id;
+  }
+
+  /**
+   * Overrides EntityFormController::buildEntity().
+   */
+  public function buildEntity(array $form, array &$form_state) {
+    $entity = clone $this->entity;
+    $entity_type = $entity->entityType();
+    $info = entity_get_info($entity_type);
+    // @todo Exploit the Field API to process the submitted entity fields.
+
+    // Copy top-level form values that are entity fields but not handled by
+    // field API without changing existing entity fields that are not being
+    // edited by this form. Values of fields handled by field API are copied
+    // by field_attach_extract_form_values() below.
+    $values_excluding_fields = $info['fieldable'] ? array_diff_key($form_state['values'], field_info_instances($entity_type, $entity->bundle())) : $form_state['values'];
+    $definitions = $entity->getPropertyDefinitions();
+    foreach ($values_excluding_fields as $key => $value) {
+      if (isset($definitions[$key])) {
+        $entity->$key = $value;
+      }
+    }
+
+    // Invoke all specified builders for copying form values to entity fields.
+    if (isset($form['#entity_builders'])) {
+      foreach ($form['#entity_builders'] as $function) {
+        call_user_func_array($function, array($entity_type, $entity, &$form, &$form_state));
+      }
+    }
+
+    // Invoke field API for copying field values.
+    if ($info['fieldable']) {
+      field_attach_extract_form_values($entity, $form, $form_state, array('langcode' => $this->getFormLangcode($form_state)));
+    }
+    return $entity;
+  }
+}
diff --git a/core/lib/Drupal/Core/Entity/ContentEntityInterface.php b/core/lib/Drupal/Core/Entity/ContentEntityInterface.php
index 9f2186f..137e6e3 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityInterface.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityInterface.php
@@ -7,9 +7,39 @@
 
 namespace Drupal\Core\Entity;
 
+use Drupal\Core\TypedData\ComplexDataInterface;
+use Drupal\Core\TypedData\TranslatableInterface;
+
 /**
  * Defines a common interface for all content entity objects.
  */
-interface ContentEntityInterface extends EntityInterface {
+interface ContentEntityInterface extends EntityInterface, RevisionableInterface, TranslatableInterface, ComplexDataInterface {
+
+  /**
+   * Marks the translation identified by the given language code as existing.
+   *
+   * @param string $langcode
+   *   The language code identifying the translation to be initialized.
+   *
+   * @todo Remove this as soon as translation metadata have been converted to
+   *    regular fields.
+   */
+  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/DatabaseStorageControllerNG.php b/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php
index 42ea348..8f482b7 100644
--- a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php
+++ b/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php
@@ -24,9 +24,7 @@
  * @todo: Once all entity types have been converted, merge improvements into the
  * DatabaseStorageController class.
  *
- * See the EntityNG documentation for an explanation of "NG".
- *
- * @see \Drupal\Core\EntityNG
+ * @see \Drupal\Core\ContentEntityBase
  */
 class DatabaseStorageControllerNG extends DatabaseStorageController {
 
diff --git a/core/lib/Drupal/Core/Entity/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php
index 68404ba..a19b4af 100644
--- a/core/lib/Drupal/Core/Entity/Entity.php
+++ b/core/lib/Drupal/Core/Entity/Entity.php
@@ -16,13 +16,8 @@
 
 /**
  * Defines a base entity class.
- *
- * Default implementation of EntityInterface.
- *
- * This class can be used as-is by simple entity types. Entity types requiring
- * special handling can extend the class.
  */
-class Entity implements IteratorAggregate, EntityInterface {
+abstract class Entity implements EntityInterface {
 
   /**
    * The language code of the entity's default language.
@@ -46,20 +41,6 @@ class Entity implements IteratorAggregate, EntityInterface {
   protected $enforceIsNew;
 
   /**
-   * Boolean indicating whether a new revision should be created on save.
-   *
-   * @var bool
-   */
-  protected $newRevision = FALSE;
-
-  /**
-   * Indicates whether this is the default revision.
-   *
-   * @var bool
-   */
-  protected $isDefaultRevision = TRUE;
-
-  /**
    * Constructs an Entity object.
    *
    * @param array $values
@@ -98,14 +79,6 @@ public function isNew() {
   }
 
   /**
-   * Implements \Drupal\Core\Entity\EntityInterface::isNewRevision().
-   */
-  public function isNewRevision() {
-    $info = $this->entityInfo();
-    return $this->newRevision || (!empty($info['entity_keys']['revision']) && !$this->getRevisionId());
-  }
-
-  /**
    * Implements \Drupal\Core\Entity\EntityInterface::enforceIsNew().
    */
   public function enforceIsNew($value = TRUE) {
@@ -113,13 +86,6 @@ public function enforceIsNew($value = TRUE) {
   }
 
   /**
-   * Implements \Drupal\Core\Entity\EntityInterface::setNewRevision().
-   */
-  public function setNewRevision($value = TRUE) {
-    $this->newRevision = $value;
-  }
-
-  /**
    * Implements \Drupal\Core\Entity\EntityInterface::entityType().
    */
   public function entityType() {
@@ -197,7 +163,7 @@ public function uriRelationships() {
   /**
    * Implements \Drupal\Core\Entity\EntityInterface::get().
    */
-  public function get($property_name, $langcode = NULL) {
+  public function get($property_name) {
     // @todo: Replace by EntityNG implementation once all entity types have been
     // converted to use the entity field API.
     return isset($this->{$property_name}) ? $this->{$property_name} : NULL;
@@ -212,62 +178,6 @@ public function set($property_name, $value, $notify = TRUE) {
     $this->{$property_name} = $value;
   }
 
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::getProperties().
-   */
-  public function getProperties($include_computed = FALSE) {
-    // @todo: Replace by EntityNG implementation once all entity types have been
-    // converted to use the entity field API.
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyValues().
-   */
-  public function getPropertyValues() {
-    // @todo: Replace by EntityNG implementation once all entity types have been
-    // converted to use the entity field API.
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::setPropertyValues().
-   */
-  public function setPropertyValues($values) {
-    // @todo: Replace by EntityNG implementation once all entity types have been
-    // converted to use the entity field API.
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinition().
-   */
-  public function getPropertyDefinition($name) {
-    // @todo: Replace by EntityNG implementation once all entity types have been
-    // converted to use the entity field API.
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions().
-   */
-  public function getPropertyDefinitions() {
-    // @todo: Replace by EntityNG implementation once all entity types have been
-    // converted to use the entity field API.
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::isEmpty().
-   */
-  public function isEmpty() {
-    // @todo: Replace by EntityNG implementation once all entity types have been
-    // converted to use the entity field API.
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::getIterator().
-   */
-  public function getIterator() {
-    // @todo: Replace by EntityNG implementation once all entity types have been
-    // converted to use the entity field API.
-    return new \ArrayIterator(array());
-  }
 
   /**
    * Implements \Drupal\Core\TypedData\AccessibleInterface::access().
@@ -284,11 +194,9 @@ public function access($operation = 'view', AccountInterface $account = NULL) {
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\TranslatableInterface::language().
+   * {@inheritdoc}
    */
   public function language() {
-    // @todo: Replace by EntityNG implementation once all entity types have been
-    // converted to use the entity field API.
     $language = language_load($this->langcode);
     if (!$language) {
       // Make sure we return a proper language object.
@@ -298,58 +206,6 @@ public function language() {
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\TranslatableInterface::getTranslation().
-   *
-   * @return \Drupal\Core\Entity\EntityInterface
-   */
-  public function getTranslation($langcode) {
-    // @todo: Replace by EntityNG implementation once all entity types have been
-    // converted to use the entity field API.
-    return $this;
-  }
-
-  /**
-   * Returns the languages the entity is translated to.
-   *
-   * @todo: Remove once all entity types implement the entity field API.
-   *   This is deprecated by
-   *   \Drupal\Core\TypedData\TranslatableInterface::getTranslationLanguages().
-   */
-  public function translations() {
-    return $this->getTranslationLanguages(FALSE);
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\TranslatableInterface::getTranslationLanguages().
-   */
-  public function getTranslationLanguages($include_default = TRUE) {
-    // @todo: Replace by EntityNG implementation once all entity types have been
-    // converted to use the entity field API.
-    $default_language = $this->language();
-    $languages = array($default_language->id => $default_language);
-    $entity_info = $this->entityInfo();
-
-    if ($entity_info['fieldable']) {
-      // Go through translatable properties and determine all languages for
-      // which translated values are available.
-      foreach (field_info_instances($this->entityType, $this->bundle()) as $field_name => $instance) {
-        if (field_is_translatable($this->entityType, $instance->getField()) && isset($this->$field_name)) {
-          foreach (array_filter($this->$field_name) as $langcode => $value)  {
-            $languages[$langcode] = TRUE;
-          }
-        }
-      }
-      $languages = array_intersect_key(language_list(Language::STATE_ALL), $languages);
-    }
-
-    if (empty($include_default)) {
-      unset($languages[$default_language->id]);
-    }
-
-    return $languages;
-  }
-
-  /**
    * Implements \Drupal\Core\Entity\EntityInterface::save().
    */
   public function save() {
@@ -389,13 +245,6 @@ public function entityInfo() {
   }
 
   /**
-   * Implements \Drupal\Core\Entity\EntityInterface::getRevisionId().
-   */
-  public function getRevisionId() {
-    return NULL;
-  }
-
-  /**
    * Implements \Drupal\Core\Entity\EntityInterface::isDefaultRevision().
    */
   public function isDefaultRevision($new_value = NULL) {
@@ -407,143 +256,6 @@ public function isDefaultRevision($new_value = NULL) {
   }
 
   /**
-   * Implements \Drupal\Core\Entity\EntityInterface::getExportProperties().
-   */
-  public function getExportProperties() {
-    return array();
-  }
-
-  /**
-   * Implements \Drupal\Core\Entity\EntityInterface::getBCEntity().
-   */
-  public function getBCEntity() {
-    return $this;
-  }
-
-  /**
-   * Implements \Drupal\Core\Entity\EntityInterface::getNGEntity().
-   */
-  public function getNGEntity() {
-    return $this;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getDefinition() {
-    // @todo: This does not make much sense, so remove once TypedDataInterface
-    // is removed. See https://drupal.org/node/2002138.
-    if ($this->bundle() != $this->entityType()) {
-      $type = 'entity:' . $this->entityType() . ':' . $this->bundle();
-    }
-    else {
-      $type = 'entity:' . $this->entityType();
-    }
-    return array('type' => $type);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getValue() {
-    // @todo: This does not make much sense, so remove once TypedDataInterface
-    // is removed. See https://drupal.org/node/2002138.
-    return $this->getPropertyValues();
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::setValue().
-   */
-  public function setValue($value, $notify = TRUE) {
-    // @todo: This does not make much sense, so remove once TypedDataInterface
-    // is removed. See https://drupal.org/node/2002138.
-    $this->setPropertyValues($value);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getString() {
-    return $this->label();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getConstraints() {
-    return array();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function validate() {
-    // @todo: Add the typed data manager as proper dependency.
-    return \Drupal::typedData()->getValidator()->validate($this);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function applyDefaultValue($notify = TRUE) {
-    foreach ($this->getProperties() as $property) {
-      $property->applyDefaultValue(FALSE);
-    }
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::onChange().
-   */
-  public function onChange($property_name) {
-    // Nothing to do.
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::getName().
-   */
-  public function getName() {
-    return NULL;
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::getRoot().
-   */
-  public function getRoot() {
-    return $this;
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::getPropertyPath().
-   */
-  public function getPropertyPath() {
-    return '';
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::getParent().
-   */
-  public function getParent() {
-    return NULL;
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\TypedDataInterface::setContext().
-   */
-  public function setContext($name = NULL, TypedDataInterface $parent = NULL) {
-    // As entities are always the root of the tree of typed data, we do not need
-    // to set any parent or name.
-  }
-
-  /**
-   * Implements \Drupal\Core\Entity\EntityInterface::isTranslatable().
-   */
-  public function isTranslatable() {
-    // @todo Inject the entity manager and retrieve bundle info from it.
-    $bundles = entity_get_bundles($this->entityType);
-    return !empty($bundles[$this->bundle()]['translatable']);
-  }
-
-  /**
    * {@inheritdoc}
    */
   public function preSave(EntityStorageControllerInterface $storage_controller) {
@@ -586,58 +298,17 @@ public static function postLoad(EntityStorageControllerInterface $storage_contro
   }
 
   /**
-   * {@inheritdoc}
-   */
-  public function preSaveRevision(EntityStorageControllerInterface $storage_controller, \stdClass $record) {
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getUntranslated() {
-    return $this->getTranslation(Language::LANGCODE_DEFAULT);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function hasTranslation($langcode) {
-    $translations = $this->getTranslationLanguages();
-    return isset($translations[$langcode]);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function addTranslation($langcode, array $values = array()) {
-    // @todo Config entities do not support entity translation hence we need to
-    //   move the TranslatableInterface implementation to EntityNG. See
-    //   http://drupal.org/node/2004244
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function removeTranslation($langcode) {
-    // @todo Config entities do not support entity translation hence we need to
-    //   move the TranslatableInterface implementation to EntityNG. See
-    //   http://drupal.org/node/2004244
-  }
-
-  /**
-   * {@inheritdoc}
+   * Implements \Drupal\Core\Entity\EntityInterface::getBCEntity().
    */
-  public function initTranslation($langcode) {
-    // @todo Config entities do not support entity translation hence we need to
-    //   move the TranslatableInterface implementation to EntityNG. See
-    //   http://drupal.org/node/2004244
+  public function getBCEntity() {
+    return $this;
   }
 
   /**
-   * {@inheritdoc}
+   * Implements \Drupal\Core\Entity\EntityInterface::getNGEntity().
    */
-  public static function baseFieldDefinitions($entity_type) {
-    return array();
+  public function getNGEntity() {
+    return $this;
   }
 
 }
diff --git a/core/lib/Drupal/Core/Entity/EntityBCDecorator.php b/core/lib/Drupal/Core/Entity/EntityBCDecorator.php
index bfb13ee..f1547e7 100644
--- a/core/lib/Drupal/Core/Entity/EntityBCDecorator.php
+++ b/core/lib/Drupal/Core/Entity/EntityBCDecorator.php
@@ -38,7 +38,7 @@
  *
  * @todo: Remove once everything is converted to use the new entity field API.
  */
-class EntityBCDecorator implements IteratorAggregate, EntityInterface {
+class EntityBCDecorator implements IteratorAggregate, EntityInterface, TypedDataInterface {
 
   /**
    * The EntityInterface object being decorated.
@@ -62,7 +62,7 @@ class EntityBCDecorator implements IteratorAggregate, EntityInterface {
    * @param array &$definitions
    *   An array of field definitions.
    */
-  function __construct(EntityNG $decorated, array &$definitions) {
+  function __construct(ContentEntityBase $decorated, array &$definitions) {
     $this->decorated = $decorated;
     $this->definitions = &$definitions;
   }
@@ -112,8 +112,8 @@ public function &__get($name) {
       }
       // The returned values might be changed by reference, so we need to remove
       // the field object to avoid the field object and the value getting out of
-      // sync. That way, the next field object instantiated by EntityNG will
-      // receive the possibly updated value.
+      // sync. That way, the next field object instantiated by ContentEntityBase
+      // will receive the possibly updated value.
       unset($this->decorated->fields[$name]);
     }
     // When accessing values for entity properties that have been converted to
@@ -135,9 +135,9 @@ public function &__get($name) {
     else {
       // Allow accessing field values in an entity default language other than
       // Language::LANGCODE_DEFAULT by mapping the values to
-      // Language::LANGCODE_DEFAULT. This is necessary as EntityNG always keys
-      // default language values with Language::LANGCODE_DEFAULT while field API
-      // expects them to be keyed by langcode.
+      // Language::LANGCODE_DEFAULT. This is necessary as ContentEntityBase
+      // always keys/ default language values with Language::LANGCODE_DEFAULT
+      // while field API expects them to be keyed by langcode.
       $langcode = $this->decorated->getUntranslated()->language()->id;
       if ($langcode != Language::LANGCODE_DEFAULT && isset($this->decorated->values[$name]) && is_array($this->decorated->values[$name])) {
         if (isset($this->decorated->values[$name][Language::LANGCODE_DEFAULT]) && !isset($this->decorated->values[$name][$langcode])) {
@@ -168,9 +168,9 @@ public function __set($name, $value) {
       if ($defined && is_array($value)) {
         // If field API sets a value with a langcode in entity language, move it
         // to Language::LANGCODE_DEFAULT.
-        // This is necessary as EntityNG always keys default language values
-        // with Language::LANGCODE_DEFAULT while field API expects them to be
-        // keyed by langcode.
+        // This is necessary as ContentEntityBase always keys default language
+        // values/ with Language::LANGCODE_DEFAULT while field API expects them
+        // to be keyed by langcode.
         foreach ($value as $langcode => $data) {
           if ($langcode != Language::LANGCODE_DEFAULT && $langcode == $this->decorated->language()->id) {
             $value[Language::LANGCODE_DEFAULT] = $data;
@@ -181,8 +181,8 @@ public function __set($name, $value) {
       $this->decorated->values[$name] = $value;
     }
     // Remove the field object to avoid the field object and the value getting
-    // out of sync. That way, the next field object instantiated by EntityNG
-    // will hold the updated value.
+    // out of sync. That way, the next field object instantiated by
+    // ContentEntityBase will hold the updated value.
     unset($this->decorated->fields[$name]);
     $this->decorated->onChange($name);
   }
diff --git a/core/lib/Drupal/Core/Entity/EntityFormController.php b/core/lib/Drupal/Core/Entity/EntityFormController.php
index 07dd8f3..a6a329b 100644
--- a/core/lib/Drupal/Core/Entity/EntityFormController.php
+++ b/core/lib/Drupal/Core/Entity/EntityFormController.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Entity;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\TypedData\TranslatableInterface;
 use Drupal\entity\EntityFormDisplayInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Language\Language;
@@ -120,10 +121,6 @@ protected function init(array &$form_state) {
     // module-provided form handlers there.
     $form_state['controller'] = $this;
 
-    // Ensure we act on the translation object corresponding to the current form
-    // language.
-    $this->entity = $this->getTranslatedEntity($form_state);
-
     // Prepare the entity to be presented in the entity form.
     $this->prepareEntity();
 
@@ -268,52 +265,6 @@ protected function actions(array $form, array &$form_state) {
    * Implements \Drupal\Core\Entity\EntityFormControllerInterface::validate().
    */
   public function validate(array $form, array &$form_state) {
-    $entity = $this->buildEntity($form, $form_state);
-    $entity_type = $entity->entityType();
-    $entity_langcode = $entity->language()->id;
-
-    $violations = array();
-
-    // @todo Simplify when all entity types are converted to EntityNG.
-    if ($entity instanceof EntityNG) {
-      foreach ($entity as $field_name => $field) {
-        $field_violations = $field->validate();
-        if (count($field_violations)) {
-          $violations[$field_name] = $field_violations;
-        }
-      }
-    }
-    else {
-      // For BC entities, iterate through each field instance and
-      // instantiate NG items objects manually.
-      $definitions = \Drupal::entityManager()->getFieldDefinitions($entity_type, $entity->bundle());
-      foreach (field_info_instances($entity_type, $entity->bundle()) as $field_name => $instance) {
-        $langcode = field_is_translatable($entity_type, $instance->getField()) ? $entity_langcode : Language::LANGCODE_NOT_SPECIFIED;
-
-        // Create the field object.
-        $items = isset($entity->{$field_name}[$langcode]) ? $entity->{$field_name}[$langcode] : array();
-        // @todo Exception : calls setValue(), tries to set the 'formatted'
-        // property.
-        $field = \Drupal::typedData()->create($definitions[$field_name], $items, $field_name, $entity);
-        $field_violations = $field->validate();
-        if (count($field_violations)) {
-          $violations[$field->getName()] = $field_violations;
-        }
-      }
-    }
-
-    // Map errors back to form elements.
-    if ($violations) {
-      foreach ($violations as $field_name => $field_violations) {
-        $langcode = field_is_translatable($entity_type , field_info_field($entity_type, $field_name)) ? $entity_langcode : Language::LANGCODE_NOT_SPECIFIED;
-        $field_state = field_form_get_state($form['#parents'], $field_name, $langcode, $form_state);
-        $field_state['constraint_violations'] = $field_violations;
-        field_form_set_state($form['#parents'], $field_name, $langcode, $form_state, $field_state);
-      }
-
-      field_invoke_method('flagErrors', _field_invoke_widget_target($form_state['form_display']), $entity, $form, $form_state);
-    }
-
     // @todo Remove this.
     // Execute legacy global validation handlers.
     unset($form_state['validate_handlers']);
@@ -339,7 +290,6 @@ public function submit(array $form, array &$form_state) {
     form_state_values_clean($form_state);
 
     $this->updateFormLangcode($form_state);
-    $this->submitEntityLanguage($form, $form_state);
     $this->entity = $this->buildEntity($form, $form_state);
     return $this->entity;
   }
@@ -369,36 +319,18 @@ public function delete(array $form, array &$form_state) {
   }
 
   /**
-   * Implements \Drupal\Core\Entity\EntityFormControllerInterface::getFormLangcode().
+   * {@inheritdoc}
    */
   public function getFormLangcode(array $form_state) {
-    $entity = $this->entity;
-
-    if (!empty($form_state['langcode'])) {
-      $langcode = $form_state['langcode'];
-    }
-    else {
-      // If no form langcode was provided we default to the current content
-      // language and inspect existing translations to find a valid fallback,
-      // if any.
-      $translations = $entity->getTranslationLanguages();
-      $langcode = language(Language::TYPE_CONTENT)->id;
-      $fallback = language_multilingual() ? language_fallback_get_candidates() : array();
-      while (!empty($langcode) && !isset($translations[$langcode])) {
-        $langcode = array_shift($fallback);
-      }
-    }
-
-    // If the site is not multilingual or no translation for the given form
-    // language is available, fall back to the entity language.
-    return !empty($langcode) ? $langcode : $entity->getUntranslated()->language()->id;
+    return $this->entity->language()->id;
   }
 
   /**
    * Implements \Drupal\Core\Entity\EntityFormControllerInterface::isDefaultFormLangcode().
    */
   public function isDefaultFormLangcode(array $form_state) {
-    return $this->getFormLangcode($form_state) == $this->entity->getUntranslated()->language()->id;
+    // The entity is not translatable, this is always the default language.
+    return TRUE;
   }
 
   /**
@@ -415,42 +347,6 @@ protected function updateFormLangcode(array &$form_state) {
   }
 
   /**
-   * Handle possible entity language changes.
-   *
-   * @param array $form
-   *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   A reference to a keyed array containing the current state of the form.
-   */
-  protected function submitEntityLanguage(array $form, array &$form_state) {
-    $entity = $this->entity;
-    $entity_type = $entity->entityType();
-
-    if (field_has_translation_handler($entity_type)) {
-      // If we are editing the default language values, we use the submitted
-      // entity language as the new language for fields to handle any language
-      // change. Otherwise the current form language is the proper value, since
-      // in this case it is not supposed to change.
-      $current_langcode = $this->isDefaultFormLangcode($form_state) ? $form_state['values']['langcode'] : $this->getFormLangcode($form_state);
-
-      foreach (field_info_instances($entity_type, $entity->bundle()) as $instance) {
-        $field = $instance->getField();
-        $field_name = $field->name;
-        if (isset($form[$field_name]['#language'])) {
-          $previous_langcode = $form[$field_name]['#language'];
-
-          // Handle a possible language change: new language values are inserted,
-          // previous ones are deleted.
-          if ($field['translatable'] && $previous_langcode != $current_langcode) {
-            $form_state['values'][$field_name][$current_langcode] = $form_state['values'][$field_name][$previous_langcode];
-            $form_state['values'][$field_name][$previous_langcode] = array();
-          }
-        }
-      }
-    }
-  }
-
-  /**
    * Implements \Drupal\Core\Entity\EntityFormControllerInterface::buildEntity().
    */
   public function buildEntity(array $form, array &$form_state) {
@@ -473,17 +369,6 @@ public function getEntity() {
   }
 
   /**
-   * Returns the translation object corresponding to the form language.
-   *
-   * @param array $form_state
-   *   A keyed array containing the current state of the form.
-   */
-  protected function getTranslatedEntity(array $form_state) {
-    $langcode = $this->getFormLangcode($form_state);
-    return $this->entity->getTranslation($langcode);
-  }
-
-  /**
    * Implements \Drupal\Core\Entity\EntityFormControllerInterface::setEntity().
    */
   public function setEntity(EntityInterface $entity) {
@@ -511,7 +396,7 @@ protected function prepareInvokeAll($hook, array &$form_state) {
       if (function_exists($function)) {
         // Ensure we pass an updated translation object and form display at
         // each invocation, since they depend on form state which is alterable.
-        $args = array($this->getTranslatedEntity($form_state), $this->getFormDisplay($form_state), $this->operation, &$form_state);
+        $args = array($this->entity, $this->getFormDisplay($form_state), $this->operation, &$form_state);
         call_user_func_array($function, $args);
       }
     }
diff --git a/core/lib/Drupal/Core/Entity/EntityFormControllerNG.php b/core/lib/Drupal/Core/Entity/EntityFormControllerNG.php
deleted file mode 100644
index f760057..0000000
--- a/core/lib/Drupal/Core/Entity/EntityFormControllerNG.php
+++ /dev/null
@@ -1,84 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\Entity\EntityFormControllerNG.
- */
-
-namespace Drupal\Core\Entity;
-
-/**
- * Entity form controller variant for entity types using the new property API.
- *
- * @todo: Merge with EntityFormController and overhaul once all entity types
- * are converted to the new entity field API.
- *
- * See the EntityNG documentation for an explanation of "NG".
- *
- * @see \Drupal\Core\EntityNG
- */
-class EntityFormControllerNG extends EntityFormController {
-
-  /**
-   * Overrides EntityFormController::form().
-   */
-  public function form(array $form, array &$form_state) {
-    $entity = $this->entity;
-    // @todo Exploit the Field API to generate the default widgets for the
-    // entity fields.
-    $info = $entity->entityInfo();
-    if (!empty($info['fieldable'])) {
-      field_attach_form($entity, $form, $form_state, $this->getFormLangcode($form_state));
-    }
-
-    // Add a process callback so we can assign weights and hide extra fields.
-    $form['#process'][] = array($this, 'processForm');
-
-    return $form;
-  }
-
-  /**
-   * Overrides EntityFormController::submitEntityLanguage().
-   */
-  protected function submitEntityLanguage(array $form, array &$form_state) {
-    // Nothing to do here, as original field values are always stored with
-    // Language::LANGCODE_DEFAULT language.
-    // @todo Delete this method when merging EntityFormControllerNG with
-    //   EntityFormController.
-  }
-
-  /**
-   * Overrides EntityFormController::buildEntity().
-   */
-  public function buildEntity(array $form, array &$form_state) {
-    $entity = clone $this->entity;
-    $entity_type = $entity->entityType();
-    $info = entity_get_info($entity_type);
-    // @todo Exploit the Field API to process the submitted entity fields.
-
-    // Copy top-level form values that are entity fields but not handled by
-    // field API without changing existing entity fields that are not being
-    // edited by this form. Values of fields handled by field API are copied
-    // by field_attach_extract_form_values() below.
-    $values_excluding_fields = $info['fieldable'] ? array_diff_key($form_state['values'], field_info_instances($entity_type, $entity->bundle())) : $form_state['values'];
-    $definitions = $entity->getPropertyDefinitions();
-    foreach ($values_excluding_fields as $key => $value) {
-      if (isset($definitions[$key])) {
-        $entity->$key = $value;
-      }
-    }
-
-    // Invoke all specified builders for copying form values to entity fields.
-    if (isset($form['#entity_builders'])) {
-      foreach ($form['#entity_builders'] as $function) {
-        call_user_func_array($function, array($entity_type, $entity, &$form, &$form_state));
-      }
-    }
-
-    // Invoke field API for copying field values.
-    if ($info['fieldable']) {
-      field_attach_extract_form_values($entity, $form, $form_state, array('langcode' => $this->getFormLangcode($form_state)));
-    }
-    return $entity;
-  }
-}
diff --git a/core/lib/Drupal/Core/Entity/EntityInterface.php b/core/lib/Drupal/Core/Entity/EntityInterface.php
index 9d58820..efdf708 100644
--- a/core/lib/Drupal/Core/Entity/EntityInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityInterface.php
@@ -8,9 +8,7 @@
 namespace Drupal\Core\Entity;
 
 use Drupal\Core\TypedData\AccessibleInterface;
-use Drupal\Core\TypedData\ComplexDataInterface;
 use Drupal\Core\TypedData\IdentifiableInterface;
-use Drupal\Core\TypedData\TranslatableInterface;
 
 /**
  * Defines a common interface for all entity objects.
@@ -28,7 +26,7 @@
  * @see \Drupal\Core\TypedData\TypedDataManager
  * @see \Drupal\Core\Field\FieldInterface
  */
-interface EntityInterface extends IdentifiableInterface, ComplexDataInterface, AccessibleInterface, TranslatableInterface {
+interface EntityInterface extends IdentifiableInterface, AccessibleInterface {
 
   /**
    * Returns the entity UUID (Universally Unique Identifier).
@@ -42,6 +40,14 @@
   public function uuid();
 
   /**
+   * Returns the default language.
+   *
+   * @return
+   *   The language object.
+   */
+  public function language();
+
+  /**
    * Returns whether the entity is new.
    *
    * Usually an entity is new if no ID exists for it yet. However, entities may
@@ -55,26 +61,6 @@ public function uuid();
   public function isNew();
 
   /**
-   * Returns whether a new revision should be created on save.
-   *
-   * @return bool
-   *   TRUE if a new revision should be created.
-   *
-   * @see \Drupal\Core\Entity\EntityInterface::setNewRevision()
-   */
-  public function isNewRevision();
-
-  /**
-   * Enforces an entity to be saved as a new revision.
-   *
-   * @param bool $value
-   *   (optional) Whether a new revision should be saved.
-   *
-   * @see \Drupal\Core\Entity\EntityInterface::isNewRevision()
-   */
-  public function setNewRevision($value = TRUE);
-
-  /**
    * Enforces an entity to be new.
    *
    * Allows migrations to create entities with pre-defined IDs by forcing the
@@ -168,16 +154,6 @@ public function delete();
   public function preSave(EntityStorageControllerInterface $storage_controller);
 
   /**
-   * Acts on a revision before it gets saved.
-   *
-   * @param EntityStorageControllerInterface $storage_controller
-   *   The entity storage controller object.
-   * @param \stdClass $record
-   *   The revision object.
-   */
-  public function preSaveRevision(EntityStorageControllerInterface $storage_controller, \stdClass $record);
-
-  /**
    * Acts on a saved entity before the insert or update hook is invoked.
    *
    * Used after the entity is saved, but before invoking the insert or update
@@ -262,35 +238,6 @@ public function createDuplicate();
   public function entityInfo();
 
   /**
-   * Returns the revision identifier of the entity.
-   *
-   * @return
-   *   The revision identifier of the entity, or NULL if the entity does not
-   *   have a revision identifier.
-   */
-  public function getRevisionId();
-
-  /**
-   * Checks if this entity is the default revision.
-   *
-   * @param bool $new_value
-   *   (optional) A Boolean to (re)set the isDefaultRevision flag.
-   *
-   * @return bool
-   *   TRUE if the entity is the default revision, FALSE otherwise. If
-   *   $new_value was passed, the previous value is returned.
-   */
-  public function isDefaultRevision($new_value = NULL);
-
-  /**
-   * Retrieves the exportable properties of the entity.
-   *
-   * @return array
-   *   An array of exportable properties and their values.
-   */
-  public function getExportProperties();
-
-  /**
    * Gets a backward compatibility decorator entity.
    *
    * @return \Drupal\Core\Entity\EntityInterface
@@ -310,39 +257,4 @@ public function getBCEntity();
    */
   public function getNGEntity();
 
-  /**
-   * Returns the translation support status.
-   *
-   * @return bool
-   *   TRUE if the entity bundle has translation support enabled.
-   */
-  public function isTranslatable();
-
-  /**
-   * Marks the translation identified by the given language code as existing.
-   *
-   * @todo Remove this as soon as translation metadata have been converted to
-   *    regular fields.
-   *
-   * @param string $langcode
-   *   The language code identifying the translation to be initialized.
-   */
-  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 3060909..ab08b39 100644
--- a/core/lib/Drupal/Core/Entity/EntityManager.php
+++ b/core/lib/Drupal/Core/Entity/EntityManager.php
@@ -432,6 +432,10 @@ public function getFieldDefinitions($entity_type, $bundle = NULL) {
       }
       else {
         $class = $this->factory->getPluginClass($entity_type, $this->getDefinition($entity_type));
+        // @todo: This shouldn't be called...
+        if (!in_array('Drupal\Core\Entity\ContentEntityInterface', class_implements($class))) {
+          return array();
+        }
         $this->entityFieldInfo[$entity_type] = array(
           'definitions' => $class::baseFieldDefinitions($entity_type),
           // Contains definitions of optional (per-bundle) fields.
diff --git a/core/lib/Drupal/Core/Entity/EntityStorageControllerBase.php b/core/lib/Drupal/Core/Entity/EntityStorageControllerBase.php
index 22eb472..e54372f 100644
--- a/core/lib/Drupal/Core/Entity/EntityStorageControllerBase.php
+++ b/core/lib/Drupal/Core/Entity/EntityStorageControllerBase.php
@@ -140,35 +140,15 @@ protected function cacheSet($entities) {
    * {@inheritdoc}
    */
   public function invokeFieldMethod($method, EntityInterface $entity) {
-    foreach (array_keys($entity->getTranslationLanguages()) as $langcode) {
-      // @todo getTranslation() only works on NG entities. Remove the condition
-      // and the second code branch when all core entity types are converted.
-      if ($translation = $entity->getTranslation($langcode)) {
-        foreach ($translation as $field_name => $field) {
-          $field->$method();
-        }
-      }
-      else {
-        // For BC entities, iterate through fields and instantiate NG items
-        // objects manually.
-        $definitions = \Drupal::entityManager()->getFieldDefinitions($entity->entityType(), $entity->bundle());
-        foreach ($definitions as $field_name => $definition) {
-          if (!empty($definition['configurable'])) {
-            // Create the items object.
-            $itemsBC = isset($entity->{$field_name}[$langcode]) ? $entity->{$field_name}[$langcode] : array();
-            // @todo Exception : this calls setValue(), tries to set the
-            // 'formatted' property. For now, this is worked around by
-            // commenting out the Exception in TextProcessed::setValue().
-            $items = \Drupal::typedData()->create($definition, $itemsBC, $field_name, $entity);
-            $items->$method();
+    // Only act on content entities.
+    if (!($entity instanceof ContentEntityInterface)) {
+      return;
+    }
 
-            // Put back the items values in the entity.
-            $itemsBC = $items->getValue(TRUE);
-            if ($itemsBC !== array() || isset($entity->{$field_name}[$langcode])) {
-              $entity->{$field_name}[$langcode] = $itemsBC;
-            }
-          }
-        }
+    foreach (array_keys($entity->getTranslationLanguages()) as $langcode) {
+      $translation = $entity->getTranslation($langcode);
+      foreach ($translation as $field) {
+        $field->$method();
       }
     }
   }
@@ -177,56 +157,27 @@ public function invokeFieldMethod($method, EntityInterface $entity) {
    * {@inheritdoc}
    */
   public function invokeFieldItemPrepareCache(EntityInterface $entity) {
+    // Only act on content entities.
+    if (!($entity instanceof ContentEntityInterface)) {
+      return;
+    }
     foreach (array_keys($entity->getTranslationLanguages()) as $langcode) {
-      // @todo getTranslation() only works on NG entities. Remove the condition
-      // and the second code branch when all core entity types are converted.
-      if ($translation = $entity->getTranslation($langcode)) {
-        foreach ($translation->getPropertyDefinitions() as $property => $definition) {
-          $type_definition = \Drupal::typedData()->getDefinition($definition['type']);
-          // Only create the item objects if needed.
-          if (is_subclass_of($type_definition['class'], '\Drupal\Core\Entity\Field\PrepareCacheInterface')
-            // Prevent legacy field types from skewing performance too much by
-            // checking the existence of the legacy function directly, instead
-            // of making LegacyConfigFieldItem implement PrepareCacheInterface.
-            // @todo Remove once all core field types have been converted (see
-            // http://drupal.org/node/2014671).
-            || (is_subclass_of($type_definition['class'], '\Drupal\field\Plugin\field\field_type\LegacyConfigFieldItem') && function_exists($type_definition['provider'] . '_field_load'))) {
-
-            // Call the prepareCache() method directly on each item
-            // individually.
-            foreach ($translation->get($property) as $item) {
-              $item->prepareCache();
-            }
-          }
-        }
-      }
-      else {
-        // For BC entities, iterate through the fields and instantiate NG items
-        // objects manually.
-        $definitions = \Drupal::entityManager()->getFieldDefinitions($entity->entityType(), $entity->bundle());
-        foreach ($definitions as $field_name => $definition) {
-          if (!empty($definition['configurable'])) {
-            $type_definition = \Drupal::typedData()->getDefinition($definition['type']);
-            // Only create the item objects if needed.
-            if (is_subclass_of($type_definition['class'], '\Drupal\Core\Entity\Field\PrepareCacheInterface')
-              // @todo Remove once all core field types have been converted
-              // (see http://drupal.org/node/2014671).
-              || (is_subclass_of($type_definition['class'], '\Drupal\field\Plugin\field\field_type\LegacyConfigFieldItem') && function_exists($type_definition['provider'] . '_field_load'))) {
-
-              // Create the items object.
-              $items = isset($entity->{$field_name}[$langcode]) ? $entity->{$field_name}[$langcode] : array();
-              $itemsNG = \Drupal::typedData()->create($definition, $items, $field_name, $entity);
-
-              foreach ($itemsNG as $item) {
-                $item->prepareCache();
-              }
-
-              // Put back the items values in the entity.
-              $items = $itemsNG->getValue(TRUE);
-              if ($items !== array() || isset($entity->{$field_name}[$langcode])) {
-                $entity->{$field_name}[$langcode] = $items;
-              }
-            }
+      $translation = $entity->getTranslation($langcode);
+      foreach ($translation->getPropertyDefinitions() as $property => $definition) {
+        $type_definition = \Drupal::typedData()->getDefinition($definition['type']);
+        // Only create the item objects if needed.
+        if (is_subclass_of($type_definition['class'], '\Drupal\Core\Entity\Field\PrepareCacheInterface')
+          // Prevent legacy field types from skewing performance too much by
+          // checking the existence of the legacy function directly, instead
+          // of making LegacyConfigFieldItem implement PrepareCacheInterface.
+          // @todo Remove once all core field types have been converted (see
+          // http://drupal.org/node/2014671).
+          || (is_subclass_of($type_definition['class'], '\Drupal\field\Plugin\field\field_type\LegacyConfigFieldItem') && function_exists($type_definition['provider'] . '_field_load'))) {
+
+          // Call the prepareCache() method directly on each item
+          // individually.
+          foreach ($translation->get($property) as $item) {
+            $item->prepareCache();
           }
         }
       }
@@ -256,6 +207,10 @@ protected function invokeHook($hook, EntityInterface $entity) {
    *   The entity being saved.
    */
   protected function invokeTranslationHooks(EntityInterface $entity) {
+    // Only act on content entities.
+    if (!($entity instanceof ContentEntityInterface)) {
+      return;
+    }
     $translations = $entity->getTranslationLanguages(FALSE);
     $original_translations = $entity->original->getTranslationLanguages(FALSE);
     $all_translations = array_keys($translations + $original_translations);
diff --git a/core/lib/Drupal/Core/Entity/RevisionableInterface.php b/core/lib/Drupal/Core/Entity/RevisionableInterface.php
new file mode 100644
index 0000000..d246d24
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/RevisionableInterface.php
@@ -0,0 +1,66 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\RevisionableInterface.
+ */
+
+namespace Drupal\Core\Entity;
+
+/**
+ * Provides methods for an entity to support revisions.
+ */
+interface RevisionableInterface {
+
+  /**
+   * Returns whether a new revision should be created on save.
+   *
+   * @return bool
+   *   TRUE if a new revision should be created.
+   *
+   * @see \Drupal\Core\Entity\EntityInterface::setNewRevision()
+   */
+  public function isNewRevision();
+
+  /**
+   * Enforces an entity to be saved as a new revision.
+   *
+   * @param bool $value
+   *   (optional) Whether a new revision should be saved.
+   *
+   * @see \Drupal\Core\Entity\EntityInterface::isNewRevision()
+   */
+  public function setNewRevision($value = TRUE);
+
+  /**
+   * Returns the revision identifier of the entity.
+   *
+   * @return
+   *   The revision identifier of the entity, or NULL if the entity does not
+   *   have a revision identifier.
+   */
+  public function getRevisionId();
+
+  /**
+   * Checks if this entity is the default revision.
+   *
+   * @param bool $new_value
+   *   (optional) A Boolean to (re)set the isDefaultRevision flag.
+   *
+   * @return bool
+   *   TRUE if the entity is the default revision, FALSE otherwise. If
+   *   $new_value was passed, the previous value is returned.
+   */
+  public function isDefaultRevision($new_value = NULL);
+
+  /**
+   * Acts on a revision before it gets saved.
+   *
+   * @param EntityStorageControllerInterface $storage_controller
+   *   The entity storage controller object.
+   * @param \stdClass $record
+   *   The revision object.
+   */
+  public function preSaveRevision(EntityStorageControllerInterface $storage_controller, \stdClass $record);
+
+}
diff --git a/core/lib/Drupal/Core/TypedData/TranslatableInterface.php b/core/lib/Drupal/Core/TypedData/TranslatableInterface.php
index 0d5332b..f94aa0b 100644
--- a/core/lib/Drupal/Core/TypedData/TranslatableInterface.php
+++ b/core/lib/Drupal/Core/TypedData/TranslatableInterface.php
@@ -90,4 +90,12 @@ public function addTranslation($langcode, array $values = array());
    */
   public function removeTranslation($langcode);
 
+  /**
+   * Returns the translation support status.
+   *
+   * @return bool
+   *   TRUE if the object has translation support enabled.
+   */
+  public function isTranslatable();
+
 }
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Entity/Feed.php b/core/modules/aggregator/lib/Drupal/aggregator/Entity/Feed.php
index 610d474..648153a 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/Entity/Feed.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/Entity/Feed.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\aggregator\Entity;
 
-use Drupal\Core\Entity\EntityNG;
+use Drupal\Core\Entity\ContentEntityBase;
 use Symfony\Component\DependencyInjection\Container;
 use Drupal\Core\Entity\EntityStorageControllerInterface;
 use Drupal\Core\Entity\Annotation\EntityType;
@@ -38,7 +38,7 @@
  *   }
  * )
  */
-class Feed extends EntityNG implements FeedInterface {
+class Feed extends ContentEntityBase implements FeedInterface {
 
   /**
    * The feed ID.
@@ -142,7 +142,7 @@ class Feed extends EntityNG implements FeedInterface {
   public $block;
 
   /**
-   * Overrides Drupal\Core\Entity\EntityNG::init().
+   * {@inheritdoc}
    */
   public function init() {
     parent::init();
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Entity/Item.php b/core/modules/aggregator/lib/Drupal/aggregator/Entity/Item.php
index c24ad1e..c77b46b 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/Entity/Item.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/Entity/Item.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\aggregator\Entity;
 
-use Drupal\Core\Entity\EntityNG;
+use Drupal\Core\Entity\ContentEntityBase;
 use Drupal\Core\Entity\EntityStorageControllerInterface;
 use Drupal\Core\Entity\Annotation\EntityType;
 use Drupal\Core\Annotation\Translation;
@@ -32,7 +32,7 @@
  *   }
  * )
  */
-class Item extends EntityNG implements ItemInterface {
+class Item extends ContentEntityBase implements ItemInterface {
 
   /**
    * The feed item ID.
@@ -102,7 +102,7 @@ class Item extends EntityNG implements ItemInterface {
   public $guid;
 
   /**
-   * Overrides Drupal\Core\Entity\EntityNG::init().
+   *{@inheritdoc}
    */
   public function init() {
     parent::init();
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/FeedFormController.php b/core/modules/aggregator/lib/Drupal/aggregator/FeedFormController.php
index 577aefc..19dca39 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/FeedFormController.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/FeedFormController.php
@@ -8,13 +8,13 @@
 namespace Drupal\aggregator;
 
 use Drupal\Component\Utility\String;
-use Drupal\Core\Entity\EntityFormControllerNG;
+use Drupal\Core\Entity\ContentEntityFormController;
 use Drupal\Core\Language\Language;
 
 /**
  * Form controller for the aggregator feed edit forms.
  */
-class FeedFormController extends EntityFormControllerNG {
+class FeedFormController extends ContentEntityFormController {
 
   /**
    * {@inheritdoc}
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Form/FeedDeleteForm.php b/core/modules/aggregator/lib/Drupal/aggregator/Form/FeedDeleteForm.php
index 2fd227d..3465d2e 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/Form/FeedDeleteForm.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/Form/FeedDeleteForm.php
@@ -7,12 +7,12 @@
 
 namespace Drupal\aggregator\Form;
 
-use Drupal\Core\Entity\EntityNGConfirmFormBase;
+use Drupal\Core\Entity\ContentEntityConfirmFormBase;
 
 /**
  * Provides a form for deleting a feed.
  */
-class FeedDeleteForm extends EntityNGConfirmFormBase {
+class FeedDeleteForm extends ContentEntityConfirmFormBase {
 
   /**
    * {@inheritdoc}
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Form/FeedItemsRemoveForm.php b/core/modules/aggregator/lib/Drupal/aggregator/Form/FeedItemsRemoveForm.php
index 5dd23dc..3a7e2d3 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/Form/FeedItemsRemoveForm.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/Form/FeedItemsRemoveForm.php
@@ -7,12 +7,12 @@
 
 namespace Drupal\aggregator\Form;
 
-use Drupal\Core\Entity\EntityNGConfirmFormBase;
+use Drupal\Core\Entity\ContentEntityConfirmFormBase;
 
 /**
  * Provides a deletion confirmation form for items that belong to a feed.
  */
-class FeedItemsRemoveForm extends EntityNGConfirmFormBase {
+class FeedItemsRemoveForm extends ContentEntityConfirmFormBase {
 
   /**
    * {@inheritdoc}
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockFormController.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockFormController.php
index eb58dd6..9e20247 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockFormController.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockFormController.php
@@ -8,13 +8,13 @@
 namespace Drupal\custom_block;
 
 use Drupal\Core\Datetime\DrupalDateTime;
-use Drupal\Core\Entity\EntityFormControllerNG;
+use Drupal\Core\Entity\ContentEntityFormController;
 use Drupal\Core\Language\Language;
 
 /**
  * Form controller for the custom block edit forms.
  */
-class CustomBlockFormController extends EntityFormControllerNG {
+class CustomBlockFormController extends ContentEntityFormController {
 
   /**
    * Overrides \Drupal\Core\Entity\EntityFormController::prepareEntity().
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 698c39c..5342a57 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
@@ -7,7 +7,7 @@
 
 namespace Drupal\custom_block\Entity;
 
-use Drupal\Core\Entity\EntityNG;
+use Drupal\Core\Entity\ContentEntityBase;
 use Drupal\Core\Entity\EntityStorageControllerInterface;
 use Drupal\Core\Entity\Annotation\EntityType;
 use Drupal\Core\Annotation\Translation;
@@ -53,7 +53,7 @@
  *   }
  * )
  */
-class CustomBlock extends EntityNG implements CustomBlockInterface {
+class CustomBlock extends ContentEntityBase implements CustomBlockInterface {
 
   /**
    * The block ID.
diff --git a/core/modules/comment/lib/Drupal/comment/CommentFormController.php b/core/modules/comment/lib/Drupal/comment/CommentFormController.php
index 750f748..3852452 100644
--- a/core/modules/comment/lib/Drupal/comment/CommentFormController.php
+++ b/core/modules/comment/lib/Drupal/comment/CommentFormController.php
@@ -8,13 +8,13 @@
 namespace Drupal\comment;
 
 use Drupal\Core\Datetime\DrupalDateTime;
-use Drupal\Core\Entity\EntityFormControllerNG;
+use Drupal\Core\Entity\ContentEntityFormController;
 use Drupal\Core\Language\Language;
 
 /**
  * Base for controller for comment forms.
  */
-class CommentFormController extends EntityFormControllerNG {
+class CommentFormController extends ContentEntityFormController {
 
   /**
    * Overrides Drupal\Core\Entity\EntityFormController::form().
diff --git a/core/modules/comment/lib/Drupal/comment/Entity/Comment.php b/core/modules/comment/lib/Drupal/comment/Entity/Comment.php
index 59c122b..1735dcd 100644
--- a/core/modules/comment/lib/Drupal/comment/Entity/Comment.php
+++ b/core/modules/comment/lib/Drupal/comment/Entity/Comment.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\comment\Entity;
 
-use Drupal\Core\Entity\EntityNG;
+use Drupal\Core\Entity\ContentEntityBase;
 use Drupal\Core\Entity\Annotation\EntityType;
 use Drupal\Core\Annotation\Translation;
 use Drupal\comment\CommentInterface;
@@ -50,7 +50,7 @@
  *   }
  * )
  */
-class Comment extends EntityNG implements CommentInterface {
+class Comment extends ContentEntityBase implements CommentInterface {
 
   /**
    * The comment ID.
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigEntityTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigEntityTest.php
index faaccde..b20ba7e 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigEntityTest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigEntityTest.php
@@ -59,11 +59,9 @@ function testCRUD() {
     $this->assertIdentical($empty->get('langcode'), $default_langcode);
 
     // Verify Entity properties/methods on the newly created empty entity.
-    $this->assertIdentical($empty->isNewRevision(), FALSE);
     $this->assertIdentical($empty->entityType(), 'config_test');
     $uri = $empty->uri();
     $this->assertIdentical($uri['path'], 'admin/structure/config_test/manage/');
-    $this->assertIdentical($empty->isDefaultRevision(), TRUE);
 
     // Verify that an empty entity cannot be saved.
     try {
@@ -108,10 +106,8 @@ function testCRUD() {
     $expected['uuid'] = $config_test->uuid();
     $this->assertIdentical($config_test->label(), $expected['label']);
 
-    $this->assertIdentical($config_test->isNewRevision(), FALSE);
     $uri = $config_test->uri();
     $this->assertIdentical($uri['path'], 'admin/structure/config_test/manage/' . $expected['id']);
-    $this->assertIdentical($config_test->isDefaultRevision(), TRUE);
 
     // Verify that the entity can be saved.
     try {
diff --git a/core/modules/contact/lib/Drupal/contact/Entity/Message.php b/core/modules/contact/lib/Drupal/contact/Entity/Message.php
index 0c3c622..e6bd197 100644
--- a/core/modules/contact/lib/Drupal/contact/Entity/Message.php
+++ b/core/modules/contact/lib/Drupal/contact/Entity/Message.php
@@ -9,7 +9,7 @@
 
 use Drupal\Core\Entity\Annotation\EntityType;
 use Drupal\Core\Annotation\Translation;
-use Drupal\Core\Entity\EntityNG;
+use Drupal\Core\Entity\ContentEntityBase;
 use Drupal\contact\MessageInterface;
 
 /**
@@ -36,7 +36,7 @@
  *   }
  * )
  */
-class Message extends EntityNG implements MessageInterface {
+class Message extends ContentEntityBase implements MessageInterface {
 
   /**
    * Overrides Drupal\Core\Entity\Entity::id().
diff --git a/core/modules/contact/lib/Drupal/contact/MessageFormController.php b/core/modules/contact/lib/Drupal/contact/MessageFormController.php
index d41c959..b056dc6 100644
--- a/core/modules/contact/lib/Drupal/contact/MessageFormController.php
+++ b/core/modules/contact/lib/Drupal/contact/MessageFormController.php
@@ -7,14 +7,14 @@
 
 namespace Drupal\contact;
 
-use Drupal\Core\Entity\EntityFormControllerNG;
+use Drupal\Core\Entity\ContentEntityFormController;
 use Drupal\Core\Language\Language;
 use Drupal\user\UserInterface;
 
 /**
  * Form controller for contact message forms.
  */
-class MessageFormController extends EntityFormControllerNG {
+class MessageFormController extends ContentEntityFormController {
 
   /**
    * Overrides Drupal\Core\Entity\EntityFormController::form().
diff --git a/core/modules/contact/lib/Drupal/contact/MessageInterface.php b/core/modules/contact/lib/Drupal/contact/MessageInterface.php
index bf797e4..f4efb1c 100644
--- a/core/modules/contact/lib/Drupal/contact/MessageInterface.php
+++ b/core/modules/contact/lib/Drupal/contact/MessageInterface.php
@@ -7,12 +7,12 @@
 
 namespace Drupal\contact;
 
-use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\ContentEntityInterface;
 
 /**
  * Provides an interface defining a contant message entity
  */
-interface MessageInterface extends EntityInterface {
+interface MessageInterface extends ContentEntityInterface {
 
   /**
    * Returns the category this contact message belongs to.
diff --git a/core/modules/content_translation/content_translation.module b/core/modules/content_translation/content_translation.module
index 3edb6aa..856beb3 100644
--- a/core/modules/content_translation/content_translation.module
+++ b/core/modules/content_translation/content_translation.module
@@ -5,11 +5,13 @@
  * Allows entities to be translated into different languages.
  */
 
-use Drupal\Core\Language\Language;
-use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Entity\ContentEntityInterface;
 use Drupal\Core\Entity\EntityFormControllerInterface;
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Entity\EntityNG;
+use Drupal\Core\Entity\ContentEntityBase;
+use Drupal\Core\Language\Language;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\TypedData\TranslatableInterface;
 
 /**
  * Implements hook_help().
@@ -277,7 +279,7 @@ function _content_translation_menu_strip_loaders($path) {
  */
 function content_translation_translate_access(EntityInterface $entity) {
   $entity_type = $entity->entityType();
-  return empty($entity->getUntranslated()->language()->locked) && language_multilingual() && $entity->isTranslatable() &&
+  return $entity instanceof ContentEntityInterface && empty($entity->getUntranslated()->language()->locked) && language_multilingual() && $entity->isTranslatable() &&
     (user_access('create content translations') || user_access('update content translations') || user_access('delete content translations'));
 }
 
@@ -598,7 +600,7 @@ function content_translation_permission() {
  * Implements hook_form_alter().
  */
 function content_translation_form_alter(array &$form, array &$form_state) {
-  if (($form_controller = content_translation_form_controller($form_state)) && ($entity = $form_controller->getEntity()) && !$entity->isNew() && $entity->isTranslatable()) {
+  if (($form_controller = content_translation_form_controller($form_state)) && ($entity = $form_controller->getEntity()) && !$entity->isNew() && $entity instanceof TranslatableInterface && $entity->isTranslatable()) {
     $controller = content_translation_controller($entity->entityType());
     $controller->entityFormAlter($form, $form_state, $entity);
 
@@ -611,7 +613,7 @@ function content_translation_form_alter(array &$form, array &$form_state) {
     // translation available or a new one is being created.
     if (!$entity->isNew() && (!isset($translations[$form_langcode]) || count($translations) > 1)) {
       $entity = $entity->getNGEntity();
-      if ($entity instanceof EntityNG) {
+      if ($entity instanceof ContentEntityBase) {
         foreach ($entity->getPropertyDefinitions() as $property_name => $definition) {
           if (isset($form[$property_name])) {
             $form[$property_name]['#multilingual'] = !empty($definition['translatable']);
@@ -639,7 +641,7 @@ function content_translation_field_language_alter(&$display_language, $context)
   $entity = $context['entity'];
   $entity_type = $entity->entityType();
 
-  if (isset($entity->translation[$context['langcode']]) && $entity->isTranslatable() && !content_translation_view_access($entity, $context['langcode'])) {
+  if ($entity->getNGEntity() instanceof ContentEntityInterface && isset($entity->translation[$context['langcode']]) && $entity->isTranslatable() && !content_translation_view_access($entity, $context['langcode'])) {
     $instances = field_info_instances($entity_type, $entity->bundle());
     // Avoid altering the real entity.
     $entity = clone($entity);
@@ -675,7 +677,7 @@ function content_translation_entity_load(array $entities, $entity_type) {
 
   if (content_translation_enabled($entity_type)) {
     foreach ($entities as $entity) {
-      if ($entity->isTranslatable()) {
+      if ($entity instanceof ContentEntityInterface && $entity->isTranslatable()) {
         $enabled_entities[$entity->id()] = $entity;
       }
     }
@@ -718,7 +720,7 @@ function content_translation_load_translation_metadata(array $entities, $entity_
  */
 function content_translation_entity_insert(EntityInterface $entity) {
   // Only do something if translation support for the given entity is enabled.
-  if (!$entity->isTranslatable()) {
+  if (!($entity instanceof ContentEntityInterface) || !$entity->isTranslatable()) {
     return;
   }
 
@@ -758,7 +760,7 @@ function content_translation_entity_insert(EntityInterface $entity) {
  */
 function content_translation_entity_delete(EntityInterface $entity) {
   // Only do something if translation support for the given entity is enabled.
-  if (!$entity->isTranslatable()) {
+  if (!($entity instanceof ContentEntityInterface) || !$entity->isTranslatable()) {
     return;
   }
 
@@ -773,7 +775,7 @@ function content_translation_entity_delete(EntityInterface $entity) {
  */
 function content_translation_entity_update(EntityInterface $entity) {
   // Only do something if translation support for the given entity is enabled.
-  if (!$entity->isTranslatable()) {
+  if (!($entity instanceof ContentEntityInterface) || !$entity->isTranslatable()) {
     return;
   }
 
@@ -868,7 +870,7 @@ function content_translation_field_info_alter(&$info) {
  * Implements hook_entity_presave().
  */
 function content_translation_entity_presave(EntityInterface $entity) {
-  if ($entity->isTranslatable()) {
+  if ($entity instanceof ContentEntityInterface && $entity->isTranslatable()) {
     // @todo Avoid using request attributes once translation metadata become
     //   regular fields.
     $attributes = Drupal::request()->attributes;
diff --git a/core/modules/content_translation/content_translation.pages.inc b/core/modules/content_translation/content_translation.pages.inc
index 966d259..0e2331c 100644
--- a/core/modules/content_translation/content_translation.pages.inc
+++ b/core/modules/content_translation/content_translation.pages.inc
@@ -7,7 +7,7 @@
 
 use Drupal\Core\Language\Language;
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Entity\EntityNG;
+use Drupal\Core\Entity\ContentEntityBase;
 
 /**
  * Translations overview page callback.
@@ -238,7 +238,7 @@ function content_translation_edit_page(EntityInterface $entity, Language $langua
 function content_translation_prepare_translation(EntityInterface $entity, Language $source, Language $target) {
   // @todo Unify field and property handling.
   $entity = $entity->getNGEntity();
-  if ($entity instanceof EntityNG) {
+  if ($entity instanceof ContentEntityBase) {
     $source_translation = $entity->getTranslation($source->id);
     $entity->addTranslation($target->id, $source_translation->getPropertyValues());
   }
diff --git a/core/modules/content_translation/lib/Drupal/content_translation/FieldTranslationSynchronizer.php b/core/modules/content_translation/lib/Drupal/content_translation/FieldTranslationSynchronizer.php
index 9fd4b0e..7928a23 100644
--- a/core/modules/content_translation/lib/Drupal/content_translation/FieldTranslationSynchronizer.php
+++ b/core/modules/content_translation/lib/Drupal/content_translation/FieldTranslationSynchronizer.php
@@ -9,7 +9,7 @@
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityManager;
-use Drupal\Core\Entity\EntityNG;
+use Drupal\Core\Entity\ContentEntityBase;
 
 /**
  * Provides field translation synchronization capabilities.
@@ -39,7 +39,7 @@ public function __construct(EntityManager $entityManager) {
   public function synchronizeFields(EntityInterface $entity, $sync_langcode, $original_langcode = NULL) {
     // Field synchronization is only supported for NG entities.
     $entity = $entity->getNGEntity();
-    if (!($entity instanceof EntityNG)) {
+    if (!($entity instanceof ContentEntityBase)) {
       return;
     }
 
diff --git a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationUITest.php b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationUITest.php
index 74b779b..b051e58 100644
--- a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationUITest.php
+++ b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationUITest.php
@@ -8,7 +8,7 @@
 namespace Drupal\content_translation\Tests;
 
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Entity\EntityNG;
+use Drupal\Core\Entity\ContentEntityBase;
 use Drupal\Core\Language\Language;
 
 /**
@@ -260,7 +260,7 @@ protected function getFormSubmitAction(EntityInterface $entity) {
   protected function getTranslation(EntityInterface $entity, $langcode) {
     // @todo remove once EntityBCDecorator is gone.
     $entity = $entity->getNGEntity();
-    return $entity instanceof EntityNG ? $entity->getTranslation($langcode) : $entity;
+    return $entity instanceof ContentEntityBase ? $entity->getTranslation($langcode) : $entity;
   }
 
   /**
@@ -279,7 +279,7 @@ protected function getTranslation(EntityInterface $entity, $langcode) {
   protected function getValue(EntityInterface $translation, $property, $langcode) {
     $key = $property == 'user_id' ? 'target_id' : 'value';
     // @todo remove EntityBCDecorator condition once EntityBCDecorator is gone.
-    if (($translation instanceof EntityInterface) && !($translation instanceof EntityNG) && !($translation instanceof EntityBCDecorator)) {
+    if (($translation instanceof EntityInterface) && !($translation instanceof ContentEntityBase) && !($translation instanceof EntityBCDecorator)) {
       return is_array($translation->$property) ? $translation->{$property}[$langcode][0][$key] : $translation->$property;
     }
     else {
diff --git a/core/modules/editor/editor.module b/core/modules/editor/editor.module
index fd95b0f..81dd624 100644
--- a/core/modules/editor/editor.module
+++ b/core/modules/editor/editor.module
@@ -5,7 +5,7 @@
  * Adds bindings for client-side "text editors" to text formats.
  */
 
-use Drupal\file\Entity\File;
+use Drupal\Core\Entity\ContentEntityInterface;
 use Drupal\editor\Entity\Editor;
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Entity\EntityInterface;
@@ -392,6 +392,10 @@ function editor_pre_render_format($element) {
  * Implements hook_entity_insert().
  */
 function editor_entity_insert(EntityInterface $entity) {
+  // Only act on content entities.
+  if (!($entity instanceof ContentEntityInterface)) {
+    return;
+  }
   $referenced_files_by_field = _editor_get_file_uuids_by_field($entity);
   foreach ($referenced_files_by_field as $field => $uuids) {
     _editor_record_file_usage($uuids, $entity);
@@ -402,6 +406,11 @@ function editor_entity_insert(EntityInterface $entity) {
  * Implements hook_entity_update().
  */
 function editor_entity_update(EntityInterface $entity) {
+  // Only act on content entities.
+  if (!($entity instanceof ContentEntityInterface)) {
+    return;
+  }
+
   // On new revisions, all files are considered to be a new usage and no
   // deletion of previous file usages are necessary.
   if (!empty($entity->original) && $entity->getRevisionId() != $entity->original->getRevisionId()) {
diff --git a/core/modules/field/field.deprecated.inc b/core/modules/field/field.deprecated.inc
index 25677ac..b775f5e 100644
--- a/core/modules/field/field.deprecated.inc
+++ b/core/modules/field/field.deprecated.inc
@@ -6,7 +6,7 @@
  */
 
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Entity\EntityNG;
+use Drupal\Core\Entity\ContentEntityInterface;
 use Drupal\Core\Entity\Field\PrepareCacheInterface;
 use Drupal\Core\Language\Language;
 use Drupal\entity\Entity\EntityDisplay;
@@ -619,11 +619,7 @@ function field_attach_form(EntityInterface $entity, &$form, &$form_state, $langc
  *
  * @deprecated as of Drupal 8.0. Use the entity system instead.
  */
-function field_attach_form_validate(EntityInterface $entity, $form, &$form_state, array $options = array()) {
-  // Only support NG entities.
-  if (!($entity->getNGEntity() instanceof EntityNG)) {
-    return;
-  }
+function field_attach_form_validate(ContentEntityInterface $entity, $form, &$form_state, array $options = array()) {
 
   $has_violations = FALSE;
   foreach ($entity as $field_name => $field) {
diff --git a/core/modules/field/field.module b/core/modules/field/field.module
index 1a673bc..907f71d 100644
--- a/core/modules/field/field.module
+++ b/core/modules/field/field.module
@@ -5,7 +5,6 @@
  */
 
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Language\Language;
 use Drupal\Core\Template\Attribute;
 use Drupal\field\FieldInterface;
 use Drupal\field\FieldInstanceInterface;
diff --git a/core/modules/field/lib/Drupal/field/Plugin/field/field_type/LegacyConfigFieldItem.php b/core/modules/field/lib/Drupal/field/Plugin/field/field_type/LegacyConfigFieldItem.php
index 7c7e032..0cb2e7d 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/field/field_type/LegacyConfigFieldItem.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/field/field_type/LegacyConfigFieldItem.php
@@ -47,8 +47,8 @@ public function isEmpty() {
     // Make sure the array received by the legacy callback includes computed
     // properties.
     $item = $this->getValue(TRUE);
-    // The previous hook was never called on an empty item, but EntityNG always
-    // creates a FieldItem element for an empty field.
+    // The previous hook was never called on an empty item, but
+    // ContentEntityBase always creates a FieldItem element for an empty field.
     return empty($item) || $callback($item, $this->getInstance()->getField()->type);
   }
 
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldEditForm.php b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldEditForm.php
index 135a938..609a609 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldEditForm.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldEditForm.php
@@ -7,9 +7,8 @@
 
 namespace Drupal\field_ui\Form;
 
+use Drupal\Core\Entity\ContentEntityInterface;
 use Drupal\Core\Entity\EntityManager;
-use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Entity\EntityNG;
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\TypedData\TypedDataManager;
 use Drupal\field\FieldInfo;
@@ -161,7 +160,7 @@ public function buildForm(array $form, array &$form_state, FieldInstanceInterfac
     // FieldItem.
     $ids = (object) array('entity_type' => $this->instance['entity_type'], 'bundle' => $this->instance['bundle'], 'entity_id' => NULL);
     $entity = _field_create_entity_from_ids($ids);
-    $form['field']['settings'] += $this->getFieldItem($entity, $field['field_name'])->settingsForm($form, $form_state, $field->hasData());
+    $form['field']['settings'] += $entity->get($field['field_name'])->offsetGet(0)->settingsForm($form, $form_state, $field->hasData());
 
     $form['actions'] = array('#type' => 'actions');
     $form['actions']['submit'] = array('#type' => 'submit', '#value' => $this->t('Save field settings'));
@@ -217,28 +216,4 @@ public function submitForm(array &$form, array &$form_state) {
     }
   }
 
-  /**
-   * Returns a FieldItem object for an entity.
-   *
-   * @todo Remove when all entity types extend EntityNG.
-   *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   An entity.
-   * @param string $field_name
-   *   The field name.
-   *
-   * @return \Drupal\field\Plugin\Type\FieldType\ConfigFieldItemInterface
-   *   The field item object.
-   */
-  protected function getFieldItem(EntityInterface $entity, $field_name) {
-    if ($entity instanceof EntityNG) {
-      $item = $entity->get($field_name)->offsetGet(0);
-    }
-    else {
-      $definitions = $this->entityManager->getFieldDefinitions($entity->entityType(), $entity->bundle());
-      $item = $this->typedData->create($definitions[$field_name], array(), $field_name, $entity)->offsetGet(0);
-    }
-    return $item;
-  }
-
 }
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldInstanceEditForm.php b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldInstanceEditForm.php
index 4aff6da..a6e382a 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldInstanceEditForm.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldInstanceEditForm.php
@@ -7,9 +7,7 @@
 
 namespace Drupal\field_ui\Form;
 
-use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityManager;
-use Drupal\Core\Entity\EntityNG;
 use Drupal\Core\Form\FormBase;
 use Drupal\field\FieldInstanceInterface;
 use Drupal\field_ui\FieldUI;
@@ -80,7 +78,7 @@ public function buildForm(array $form, array &$form_state, FieldInstanceInterfac
     // Create an arbitrary entity object (used by the 'default value' widget).
     $ids = (object) array('entity_type' => $this->instance['entity_type'], 'bundle' => $this->instance['bundle'], 'entity_id' => NULL);
     $form['#entity'] = _field_create_entity_from_ids($ids);
-    $items = $this->getFieldItems($form['#entity'], $this->instance['field_name']);
+    $items = $form['#entity']->get($this->instance['field_name']);
 
     if (!empty($field['locked'])) {
       $form['locked'] = array(
@@ -165,7 +163,7 @@ public function buildForm(array $form, array &$form_state, FieldInstanceInterfac
    */
   public function validateForm(array &$form, array &$form_state) {
     if (isset($form['instance']['default_value'])) {
-      $items = $this->getFieldItems($form['#entity'], $this->instance['field_name']);
+      $items = $form['#entity']->get($this->instance['field_name']);
       $items->defaultValuesFormValidate($form['instance']['default_value'], $form, $form_state);
     }
   }
@@ -177,7 +175,7 @@ public function submitForm(array &$form, array &$form_state) {
     // Handle the default value.
     $default_value = array();
     if (isset($form['instance']['default_value'])) {
-      $items = $this->getFieldItems($form['#entity'], $this->instance['field_name']);
+      $items = $form['#entity']->get($this->instance['field_name']);
       $default_value = $items->defaultValuesFormSubmit($form['instance']['default_value'], $form, $form_state);
     }
     $this->instance['default_value'] = $default_value;
@@ -206,28 +204,6 @@ public function delete(array &$form, array &$form_state) {
   }
 
   /**
-   * Returns a Field object for an entity.
-   *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   An entity.
-   * @param string $field_name
-   *   The field name.
-   *
-   * @return \Drupal\field\Plugin\Type\FieldType\ConfigFieldInterface
-   *   The field object.
-   */
-  protected function getFieldItems(EntityInterface $entity, $field_name) {
-    if ($entity instanceof EntityNG) {
-      $item = $entity->get($field_name);
-    }
-    else {
-      $definitions = \Drupal::entityManager()->getFieldDefinitions($entity->entityType(), $entity->bundle());
-      $item = \Drupal::typedData()->create($definitions[$field_name], $this->instance->default_value, $field_name, $entity);
-    }
-    return $item;
-  }
-
-  /**
    * Returns the next redirect path in a multipage sequence.
    *
    * @return string|array
diff --git a/core/modules/file/lib/Drupal/file/Entity/File.php b/core/modules/file/lib/Drupal/file/Entity/File.php
index 833f2db..9ec7e30 100644
--- a/core/modules/file/lib/Drupal/file/Entity/File.php
+++ b/core/modules/file/lib/Drupal/file/Entity/File.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\file\Entity;
 
-use Drupal\Core\Entity\EntityNG;
+use Drupal\Core\Entity\ContentEntityBase;
 use Drupal\Core\Entity\Annotation\EntityType;
 use Drupal\Core\Entity\EntityStorageControllerInterface;
 use Drupal\Core\Annotation\Translation;
@@ -34,7 +34,7 @@
  *   }
  * )
  */
-class File extends EntityNG implements FileInterface {
+class File extends ContentEntityBase implements FileInterface {
 
   /**
    * The plain data values of the contained properties.
diff --git a/core/modules/hal/lib/Drupal/hal/Normalizer/EntityNormalizer.php b/core/modules/hal/lib/Drupal/hal/Normalizer/EntityNormalizer.php
index 751de28..4ee475b 100644
--- a/core/modules/hal/lib/Drupal/hal/Normalizer/EntityNormalizer.php
+++ b/core/modules/hal/lib/Drupal/hal/Normalizer/EntityNormalizer.php
@@ -8,7 +8,7 @@
 namespace Drupal\hal\Normalizer;
 
 use Drupal\Component\Utility\NestedArray;
-use Drupal\Core\Entity\EntityNG;
+use Drupal\Core\Entity\ContentEntityBase;
 use Drupal\Core\Language\Language;
 use Symfony\Component\Serializer\Exception\UnexpectedValueException;
 
diff --git a/core/modules/menu_link/lib/Drupal/menu_link/Entity/MenuLink.php b/core/modules/menu_link/lib/Drupal/menu_link/Entity/MenuLink.php
index d6493f5..9f0de30 100644
--- a/core/modules/menu_link/lib/Drupal/menu_link/Entity/MenuLink.php
+++ b/core/modules/menu_link/lib/Drupal/menu_link/Entity/MenuLink.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\menu_link\Entity;
 
+use Drupal\Core\Language\Language;
 use Drupal\menu_link\MenuLinkInterface;
 use Symfony\Component\Routing\Route;
 use Symfony\Component\HttpFoundation\Request;
@@ -271,6 +272,70 @@ class MenuLink extends Entity implements \ArrayAccess, MenuLinkInterface {
   protected $routeObject;
 
   /**
+   * Boolean indicating whether a new revision should be created on save.
+   *
+   * @var bool
+   */
+  protected $newRevision = FALSE;
+
+  /**
+   * Indicates whether this is the default revision.
+   *
+   * @var bool
+   */
+  protected $isDefaultRevision = TRUE;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setNewRevision($value = TRUE) {
+    $this->newRevision = $value;
+  }
+  /**
+   * {@inheritdoc}
+   */
+  public function isNewRevision() {
+    $info = $this->entityInfo();
+    return $this->newRevision || (!empty($info['entity_keys']['revision']) && !$this->getRevisionId());
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getRevisionId() {
+    return NULL;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isTranslatable() {
+    // @todo Inject the entity manager and retrieve bundle info from it.
+    $bundles = entity_get_bundles($this->entityType);
+    return !empty($bundles[$this->bundle()]['translatable']);
+  }
+
+  /**
+   * Implements \Drupal\Core\TypedData\TranslatableInterface::language().
+   */
+  public function language() {
+    // @todo: Replace by EntityNG implementation once all entity types have been
+    // converted to use the entity field API.
+    $language = language_load($this->langcode);
+    if (!$language) {
+      // Make sure we return a proper language object.
+      $language = new Language(array('id' => Language::LANGCODE_NOT_SPECIFIED));
+    }
+    return $language;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function preSaveRevision(EntityStorageControllerInterface $storage_controller, \stdClass $record) {
+  }
+
+  /**
    * Overrides Entity::id().
    */
   public function id() {
diff --git a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkInterface.php b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkInterface.php
index b8e639e..fcf5415 100644
--- a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkInterface.php
+++ b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkInterface.php
@@ -15,7 +15,7 @@
 /**
  * Provides an interface defining a menu link entity.
  */
-interface MenuLinkInterface extends ContentEntityInterface {
+interface MenuLinkInterface extends EntityInterface {
 
   /**
    * Returns the Route object associated with this link, if any.
diff --git a/core/modules/node/lib/Drupal/node/Entity/Node.php b/core/modules/node/lib/Drupal/node/Entity/Node.php
index e44fa17..405d2cd 100644
--- a/core/modules/node/lib/Drupal/node/Entity/Node.php
+++ b/core/modules/node/lib/Drupal/node/Entity/Node.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\node\Entity;
 
-use Drupal\Core\Entity\EntityNG;
+use Drupal\Core\Entity\ContentEntityBase;
 use Drupal\Core\Entity\EntityStorageControllerInterface;
 use Drupal\Core\Entity\Annotation\EntityType;
 use Drupal\Core\Annotation\Translation;
@@ -57,7 +57,7 @@
  *   }
  * )
  */
-class Node extends EntityNG implements NodeInterface {
+class Node extends ContentEntityBase implements NodeInterface {
 
   /**
    * Implements Drupal\Core\Entity\EntityInterface::id().
diff --git a/core/modules/node/lib/Drupal/node/Form/NodeDeleteForm.php b/core/modules/node/lib/Drupal/node/Form/NodeDeleteForm.php
index bfd3a1b..583c089 100644
--- a/core/modules/node/lib/Drupal/node/Form/NodeDeleteForm.php
+++ b/core/modules/node/lib/Drupal/node/Form/NodeDeleteForm.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\node\Form;
 
-use Drupal\Core\Entity\EntityNGConfirmFormBase;
+use Drupal\Core\Entity\ContentEntityConfirmFormBase;
 use Drupal\Core\Entity\EntityStorageControllerInterface;
 use Drupal\Core\Routing\UrlGeneratorInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -15,7 +15,7 @@
 /**
  * Provides a form for deleting a node.
  */
-class NodeDeleteForm extends EntityNGConfirmFormBase {
+class NodeDeleteForm extends ContentEntityConfirmFormBase {
 
   /**
    * The URL generator.
diff --git a/core/modules/node/lib/Drupal/node/NodeAccessController.php b/core/modules/node/lib/Drupal/node/NodeAccessController.php
index b1f120a..a2d4b93 100644
--- a/core/modules/node/lib/Drupal/node/NodeAccessController.php
+++ b/core/modules/node/lib/Drupal/node/NodeAccessController.php
@@ -14,7 +14,7 @@
 use Drupal\Core\Language\Language;
 use Drupal\Core\Entity\EntityAccessController;
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Entity\EntityNG;
+use Drupal\Core\Entity\ContentEntityBase;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\user\Entity\User;
 use Symfony\Component\DependencyInjection\ContainerInterface;
diff --git a/core/modules/node/lib/Drupal/node/NodeFormController.php b/core/modules/node/lib/Drupal/node/NodeFormController.php
index 0609e9c..62ce821 100644
--- a/core/modules/node/lib/Drupal/node/NodeFormController.php
+++ b/core/modules/node/lib/Drupal/node/NodeFormController.php
@@ -9,13 +9,13 @@
 
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Datetime\DrupalDateTime;
-use Drupal\Core\Entity\EntityFormControllerNG;
+use Drupal\Core\Entity\ContentEntityFormController;
 use Drupal\Core\Language\Language;
 
 /**
  * Form controller for the node edit forms.
  */
-class NodeFormController extends EntityFormControllerNG {
+class NodeFormController extends ContentEntityFormController {
 
   /**
    * Default settings for this content/node type.
diff --git a/core/modules/node/lib/Drupal/node/NodeGrantDatabaseStorage.php b/core/modules/node/lib/Drupal/node/NodeGrantDatabaseStorage.php
index 094c262..da98af9 100644
--- a/core/modules/node/lib/Drupal/node/NodeGrantDatabaseStorage.php
+++ b/core/modules/node/lib/Drupal/node/NodeGrantDatabaseStorage.php
@@ -10,7 +10,7 @@
 use Drupal\Core\Database\Connection;
 use Drupal\Core\Database\Query\SelectInterface;
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Entity\EntityNG;
+use Drupal\Core\Entity\ContentEntityBase;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\user\Entity\User;
diff --git a/core/modules/path/path.module b/core/modules/path/path.module
index e6a1063..9f1f34b 100644
--- a/core/modules/path/path.module
+++ b/core/modules/path/path.module
@@ -7,6 +7,7 @@
 
 use Drupal\Core\Language\Language;
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\ContentEntityInterface;
 
 /**
  * Implements hook_help().
@@ -238,7 +239,7 @@ function path_entity_field_info($entity_type) {
  * @todo: Move this to methods on the FieldItem class.
  */
 function path_entity_insert(EntityInterface $entity) {
-  if ($entity->getPropertyDefinition('path')) {
+  if ($entity instanceof ContentEntityInterface && $entity->getPropertyDefinition('path')) {
     $entity->path->alias = trim($entity->path->alias);
     // Only save a non-empty alias.
     if (!empty($entity->path->alias)) {
@@ -254,7 +255,7 @@ function path_entity_insert(EntityInterface $entity) {
  * Implements hook_entity_update().
  */
 function path_entity_update(EntityInterface $entity) {
-  if ($entity->getPropertyDefinition('path')) {
+  if ($entity instanceof ContentEntityInterface && $entity->getPropertyDefinition('path')) {
     $entity->path->alias = trim($entity->path->alias);
     // Delete old alias if user erased it.
     if ($entity->path->pid && !$entity->path->alias) {
@@ -275,7 +276,7 @@ function path_entity_update(EntityInterface $entity) {
  * Implements hook_entity_predelete().
  */
 function path_entity_predelete(EntityInterface $entity) {
-  if ($entity->getPropertyDefinition('path')) {
+  if ($entity instanceof ContentEntityInterface && $entity->getPropertyDefinition('path')) {
     // Delete all aliases associated with this term.
     $uri = $entity->uri();
     Drupal::service('path.crud')->delete(array('source' => $uri['path']));
diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/Field/FieldRdfaTestBase.php b/core/modules/rdf/lib/Drupal/rdf/Tests/Field/FieldRdfaTestBase.php
index af2aeb9..5c885f7 100644
--- a/core/modules/rdf/lib/Drupal/rdf/Tests/Field/FieldRdfaTestBase.php
+++ b/core/modules/rdf/lib/Drupal/rdf/Tests/Field/FieldRdfaTestBase.php
@@ -34,7 +34,7 @@
   /**
    * The entity to render for testing.
    *
-   * @var \Drupal\Core\Entity\EntityNG
+   * @var \Drupal\Core\Entity\ContentEntityBase
    */
   protected $entity;
 
@@ -87,7 +87,7 @@ protected function createTestField() {
   /**
    * Gets the absolute URI of an entity.
    *
-   * @param \Drupal\Core\Entity\EntityNG $entity
+   * @param \Drupal\Core\Entity\ContentEntityBase $entity
    *   The entity for which to generate the URI.
    *
    * @return string
diff --git a/core/modules/serialization/lib/Drupal/serialization/Tests/EntitySerializationTest.php b/core/modules/serialization/lib/Drupal/serialization/Tests/EntitySerializationTest.php
index c8a4862..2b08044 100644
--- a/core/modules/serialization/lib/Drupal/serialization/Tests/EntitySerializationTest.php
+++ b/core/modules/serialization/lib/Drupal/serialization/Tests/EntitySerializationTest.php
@@ -29,7 +29,7 @@ class EntitySerializationTest extends NormalizerTestBase {
   /**
    * The test entity.
    *
-   * @var \Drupal\Core\Entity\EntityNG
+   * @var \Drupal\Core\Entity\ContentEntityBase
    */
   protected $entity;
 
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 95d74ce..0aff9bf 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
@@ -7,7 +7,7 @@
 
 namespace Drupal\entity_test\Entity;
 
-use Drupal\Core\Entity\EntityNG;
+use Drupal\Core\Entity\ContentEntityBase;
 use Drupal\Core\Entity\Annotation\EntityType;
 use Drupal\Core\Annotation\Translation;
 use Drupal\Core\Language\Language;
@@ -39,7 +39,7 @@
  *   menu_base_path = "entity-test/manage/%entity_test"
  * )
  */
-class EntityTest extends EntityNG {
+class EntityTest extends ContentEntityBase {
 
   /**
    * The entity ID.
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 b4a064f..37f4acb 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
@@ -39,64 +39,4 @@
  */
 class EntityTestCache extends EntityTest {
 
-  /**
-   * The entity ID.
-   *
-   * @var \Drupal\Core\Entity\Field\FieldInterface
-   */
-  public $id;
-
-  /**
-   * The entity UUID.
-   *
-   * @var \Drupal\Core\Entity\Field\FieldInterface
-   */
-  public $uuid;
-
-  /**
-   * The bundle of the test entity.
-   *
-   * @var \Drupal\Core\Entity\Field\FieldInterface
-   */
-  public $type;
-
-  /**
-   * The name of the test entity.
-   *
-   * @var \Drupal\Core\Entity\Field\FieldInterface
-   */
-  public $name;
-
-  /**
-   * The associated user.
-   *
-   * @var \Drupal\Core\Entity\Field\FieldInterface
-   */
-  public $user_id;
-
-  /**
-   * Initialize the object. Invoked upon construction and wake up.
-   */
-  protected function init() {
-    parent::init();
-    // We unset all defined properties, so magic getters apply.
-    unset($this->id);
-    unset($this->uuid);
-    unset($this->name);
-    unset($this->user_id);
-    unset($this->type);
-  }
-
-  /**
-   * Overrides Drupal\entity\Entity::label().
-   */
-  public function label($langcode = Language::LANGCODE_DEFAULT) {
-    $info = $this->entityInfo();
-    if (isset($info['entity_keys']['label']) && $info['entity_keys']['label'] == 'name') {
-      return $this->getTranslation($langcode)->name->value;
-    }
-    else {
-      return parent::label($langcode);
-    }
-  }
 }
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestFormController.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestFormController.php
index 1dbb859..e54520c 100644
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestFormController.php
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestFormController.php
@@ -6,13 +6,13 @@
 
 namespace Drupal\entity_test;
 
-use Drupal\Core\Entity\EntityFormControllerNG;
+use Drupal\Core\Entity\ContentEntityFormController;
 use Drupal\Core\Language\Language;
 
 /**
  * Form controller for the test entity edit forms.
  */
-class EntityTestFormController extends EntityFormControllerNG {
+class EntityTestFormController extends ContentEntityFormController {
 
   /**
    * Overrides Drupal\Core\Entity\EntityFormController::form().
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Entity/Term.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Entity/Term.php
index daeb3ac..1994616 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Entity/Term.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Entity/Term.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\taxonomy\Entity;
 
-use Drupal\Core\Entity\EntityNG;
+use Drupal\Core\Entity\ContentEntityBase;
 use Drupal\Core\Entity\Annotation\EntityType;
 use Drupal\Core\Entity\EntityStorageControllerInterface;
 use Drupal\Core\Annotation\Translation;
@@ -54,7 +54,7 @@
  *   permission_granularity = "bundle"
  * )
  */
-class Term extends EntityNG implements TermInterface {
+class Term extends ContentEntityBase implements TermInterface {
 
   /**
    * The taxonomy term ID.
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Form/TermDeleteForm.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Form/TermDeleteForm.php
index 032ee21..dde4abe 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Form/TermDeleteForm.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Form/TermDeleteForm.php
@@ -9,13 +9,13 @@
 
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Drupal\taxonomy\VocabularyStorageControllerInterface;
-use Drupal\Core\Entity\EntityNGConfirmFormBase;
+use Drupal\Core\Entity\ContentEntityConfirmFormBase;
 use Drupal\Core\Cache\Cache;
 
 /**
  * Provides a deletion confirmation form for taxonomy term.
  */
-class TermDeleteForm extends EntityNGConfirmFormBase {
+class TermDeleteForm extends ContentEntityConfirmFormBase {
 
   /**
    * The taxonomy vocabulary storage controller.
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/TermFormController.php b/core/modules/taxonomy/lib/Drupal/taxonomy/TermFormController.php
index aa104d4..4e7f31d 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/TermFormController.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/TermFormController.php
@@ -9,14 +9,14 @@
 
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Config\ConfigFactory;
-use Drupal\Core\Entity\EntityFormControllerNG;
+use Drupal\Core\Entity\ContentEntityFormController;
 use Drupal\Core\Language\Language;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Base for controller for taxonomy term edit forms.
  */
-class TermFormController extends EntityFormControllerNG {
+class TermFormController extends ContentEntityFormController {
 
   /**
    * The vocabulary storage.
diff --git a/core/modules/user/lib/Drupal/user/AccountFormController.php b/core/modules/user/lib/Drupal/user/AccountFormController.php
index 138b86e..b9fe6e3 100644
--- a/core/modules/user/lib/Drupal/user/AccountFormController.php
+++ b/core/modules/user/lib/Drupal/user/AccountFormController.php
@@ -7,13 +7,13 @@
 
 namespace Drupal\user;
 
-use Drupal\Core\Entity\EntityFormControllerNG;
+use Drupal\Core\Entity\ContentEntityFormController;
 use Drupal\Core\Language\Language;
 
 /**
  * Form controller for the user account forms.
  */
-abstract class AccountFormController extends EntityFormControllerNG {
+abstract class AccountFormController extends ContentEntityFormController {
 
   /**
    * {@inheritdoc}
diff --git a/core/modules/user/lib/Drupal/user/Entity/User.php b/core/modules/user/lib/Drupal/user/Entity/User.php
index 3f1a54f..b4588db 100644
--- a/core/modules/user/lib/Drupal/user/Entity/User.php
+++ b/core/modules/user/lib/Drupal/user/Entity/User.php
@@ -7,9 +7,9 @@
 
 namespace Drupal\user\Entity;
 
+use Drupal\Core\Entity\ContentEntityBase;
 use Drupal\Core\Entity\EntityStorageControllerInterface;
 use Drupal\Core\Entity\EntityMalformedException;
-use Drupal\Core\Entity\EntityNG;
 use Drupal\Core\Entity\Annotation\EntityType;
 use Drupal\Core\Annotation\Translation;
 use Drupal\user\UserInterface;
@@ -47,7 +47,7 @@
  *   }
  * )
  */
-class User extends EntityNG implements UserInterface {
+class User extends ContentEntityBase implements UserInterface {
 
   /**
    * {@inheritdoc}
diff --git a/core/modules/user/lib/Drupal/user/UserInterface.php b/core/modules/user/lib/Drupal/user/UserInterface.php
index 3400abf..4fbe5b3 100644
--- a/core/modules/user/lib/Drupal/user/UserInterface.php
+++ b/core/modules/user/lib/Drupal/user/UserInterface.php
@@ -7,13 +7,13 @@
 
 namespace Drupal\user;
 
-use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\ContentEntityInterface;
 use Drupal\Core\Session\AccountInterface;
 
 /**
  * Provides an interface defining a user entity.
  */
-interface UserInterface extends EntityInterface, AccountInterface {
+interface UserInterface extends ContentEntityInterface, AccountInterface {
 
   /**
    * Returns a list of roles.
diff --git a/core/modules/views/lib/Drupal/views/ViewStorageInterface.php b/core/modules/views/lib/Drupal/views/ViewStorageInterface.php
index 7009bae..089f428 100644
--- a/core/modules/views/lib/Drupal/views/ViewStorageInterface.php
+++ b/core/modules/views/lib/Drupal/views/ViewStorageInterface.php
@@ -12,7 +12,7 @@
 /**
  * Defines an interface for View storage classes.
  */
-interface ViewStorageInterface extends \IteratorAggregate, ConfigEntityInterface {
+interface ViewStorageInterface extends ConfigEntityInterface {
 
   /**
    * Retrieves a specific display's configuration by reference.
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 75deeba..aa65f56 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/ViewUI.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/ViewUI.php
@@ -793,13 +793,6 @@ public function &getDisplay($display_id) {
   }
 
   /**
-   * Implements \IteratorAggregate::getIterator().
-   */
-  public function getIterator() {
-    return $this->storage->getIterator();
-  }
-
-  /**
    * Implements \Drupal\Core\Entity\EntityInterface::id().
    */
   public function id() {
@@ -835,20 +828,6 @@ public function bundle() {
   }
 
   /**
-   * Implements \Drupal\Core\Entity\EntityInterface::isDefaultRevision().
-   */
-  public function isDefaultRevision($new_value = NULL) {
-    return $this->storage->isDefaultRevision($new_value);
-  }
-
-  /**
-   * Implements \Drupal\Core\Entity\EntityInterface::getRevisionId().
-   */
-  public function getRevisionId() {
-    return $this->storage->getRevisionId();
-  }
-
-  /**
    * Implements \Drupal\Core\Entity\EntityInterface::entityInfo().
    */
   public function entityInfo() {
@@ -891,20 +870,6 @@ public function label($langcode = NULL) {
   }
 
   /**
-   * Implements \Drupal\Core\Entity\EntityInterface::isNewRevision().
-   */
-  public function isNewRevision() {
-    return $this->storage->isNewRevision();
-  }
-
-  /**
-   * Implements \Drupal\Core\Entity\EntityInterface::setNewRevision().
-   */
-  public function setNewRevision($value = TRUE) {
-    return $this->storage->setNewRevision($value);
-  }
-
-  /**
    * Implements \Drupal\Core\Entity\EntityInterface::enforceIsNew().
    */
   public function enforceIsNew($value = TRUE) {
@@ -918,23 +883,9 @@ public function getExportProperties() {
     return $this->storage->getExportProperties();
   }
 
-  /**
-   * Implements \Drupal\Core\TypedData\TranslatableInterface::getTranslation().
-   */
-  public function getTranslation($langcode) {
-    // @todo Revisit this once config entities are converted to NG.
-    return $this;
-  }
 
   /**
-   * Implements \Drupal\Core\TypedData\TranslatableInterface::getTranslationLanguages().
-   */
-  public function getTranslationLanguages($include_default = TRUE) {
-    return $this->storage->getTranslationLanguages($include_default);
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\TranslatableInterface::language)().
+   * {@inheritdoc}
    */
   public function language() {
     return $this->storage->language();
@@ -948,48 +899,6 @@ public function access($operation = 'view', AccountInterface $account = NULL) {
   }
 
   /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::isEmpty)().
-   */
-  public function isEmpty() {
-    return $this->storage->isEmpty();
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyValues().
-   */
-  public function getPropertyValues() {
-    return $this->storage->getPropertyValues();
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions().
-   */
-  public function getPropertyDefinitions() {
-    return $this->storage->getPropertyDefinitions();
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinition().
-   */
-  public function getPropertyDefinition($name) {
-    return $this->storage->getPropertyDefinition($name);
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::setPropertyValues().
-   */
-  public function setPropertyValues($values) {
-    return $this->storage->setPropertyValues($values);
-  }
-
-  /**
-   * Implements \Drupal\Core\TypedData\ComplexDataInterface::getProperties().
-   */
-  public function getProperties($include_computed = FALSE) {
-    return $this->storage->getProperties($include_computed);
-  }
-
-  /**
    * Implements \Drupal\Core\Config\Entity\ConfigEntityInterface::enable().
    */
   public function enable() {
@@ -1219,13 +1128,6 @@ public static function postLoad(EntityStorageControllerInterface $storage_contro
   /**
    * {@inheritdoc}
    */
-  public function preSaveRevision(EntityStorageControllerInterface $storage_controller, \stdClass $record) {
-    $this->storage->preSaveRevision($storage_controller, $record);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function mergeDefaultDisplaysOptions() {
     $this->storage->mergeDefaultDisplaysOptions();
   }
@@ -1237,13 +1139,4 @@ 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
-    //   https://drupal.org/node/2004244.
-    return array();
-  }
 }
diff --git a/core/modules/views_ui/tests/Drupal/views_ui/Tests/ViewUIObjectTest.php b/core/modules/views_ui/tests/Drupal/views_ui/Tests/ViewUIObjectTest.php
index 9b52116..18a383f 100644
--- a/core/modules/views_ui/tests/Drupal/views_ui/Tests/ViewUIObjectTest.php
+++ b/core/modules/views_ui/tests/Drupal/views_ui/Tests/ViewUIObjectTest.php
@@ -39,10 +39,8 @@ public function testEntityDecoration() {
     $method_args = array();
     $method_args['setOriginalID'] = array(12);
     $method_args['setStatus'] = array(TRUE);
-    $method_args['setNewRevision'] = array(FALSE);
     $method_args['enforceIsNew'] = array(FALSE);
     $method_args['label'] = array(Language::LANGCODE_NOT_SPECIFIED);
-    $method_args['isDefaultRevision'] = array(TRUE);
 
     $reflection = new \ReflectionClass('Drupal\Core\Config\Entity\ConfigEntityInterface');
     $interface_methods = array();
