diff --git a/core/includes/entity.inc b/core/includes/entity.inc
index 37fb310..7d18e13 100644
--- a/core/includes/entity.inc
+++ b/core/includes/entity.inc
@@ -43,6 +43,7 @@ function entity_info_cache_clear() {
   drupal_static_reset('entity_get_bundles');
   // Clear all languages.
   drupal_container()->get('plugin.manager.entity')->clearCachedDefinitions();
+  drupal_container()->get('plugin.manager.entity')->resetControllers();
 }
 
 /**
diff --git a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php b/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php
index e8998f8..063f413 100644
--- a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php
+++ b/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php
@@ -96,6 +96,8 @@ public function __construct($entityType) {
    */
   public function create(array $values) {
     // We have to determine the bundle first.
+    // @todo Throw an exception if no bundle is passed and we have a bundle key
+    //   defined.
     $bundle = $this->bundleKey ? $values[$this->bundleKey] : FALSE;
     $entity = new $this->entityClass(array(), $this->entityType, $bundle);
 
@@ -154,7 +156,7 @@ protected function attachLoad(&$queried_entities, $load_revision = FALSE) {
     // Map the loaded stdclass records into entity objects and according fields.
     $queried_entities = $this->mapFromStorageRecords($queried_entities, $load_revision);
 
-    // Attach fields.
+    // Activate backward-compatibility mode to attach fields.
     if ($this->entityInfo['fieldable']) {
       // Prepare BC compatible entities before passing them to the field API.
       $bc_entities = array();
@@ -270,6 +272,12 @@ protected function attachPropertyData(array &$entities, $load_revision = FALSE)
   public function save(EntityInterface $entity) {
     $transaction = db_transaction();
     try {
+      // Ensure we are dealing with the actual entity.
+      $entity = $entity->getOriginalEntity();
+
+      // Sync the changes made in the fields array to the internal values array.
+      $entity->updateOriginalValues();
+
       // Load the stored entity, if any.
       if (!$entity->isNew() && !isset($entity->original)) {
         $entity->original = entity_load_unchanged($this->entityType, $entity->id());
@@ -279,7 +287,7 @@ public function save(EntityInterface $entity) {
       $this->invokeHook('presave', $entity);
 
       // Create the storage record to be saved.
-      $record = $this->maptoStorageRecord($entity);
+      $record = $this->mapToStorageRecord($entity);
 
       if (!$entity->isNew()) {
         if ($entity->isDefaultRevision()) {
@@ -446,7 +454,9 @@ protected function mapToStorageRecord(EntityInterface $entity) {
   protected function mapToRevisionStorageRecord(EntityInterface $entity) {
     $record = new \stdClass();
     foreach ($this->entityInfo['schema_fields_sql']['revision_table'] as $name) {
-      $record->$name = $entity->$name->value;
+      if (isset($entity->$name->value)) {
+        $record->$name = $entity->$name->value;
+      }
     }
     return $record;
   }
@@ -489,6 +499,11 @@ public function delete(array $entities) {
 
     $transaction = db_transaction();
     try {
+      // Ensure we are dealing with the actual entities.
+      foreach ($entities as $id => $entity) {
+        $entities[$id] = $entity->getOriginalEntity();
+      }
+
       $this->preDelete($entities);
       foreach ($entities as $id => $entity) {
         $this->invokeHook('predelete', $entity);
diff --git a/core/lib/Drupal/Core/Entity/EntityBCDecorator.php b/core/lib/Drupal/Core/Entity/EntityBCDecorator.php
index 57215cb..31fb456 100644
--- a/core/lib/Drupal/Core/Entity/EntityBCDecorator.php
+++ b/core/lib/Drupal/Core/Entity/EntityBCDecorator.php
@@ -46,13 +46,23 @@ class EntityBCDecorator implements IteratorAggregate, EntityInterface {
   protected $decorated;
 
   /**
+   * Local cache for field definitions.
+   *
+   * @var array
+   */
+  protected $definitions;
+
+  /**
    * Constructs a Drupal\Core\Entity\EntityCompatibilityDecorator object.
    *
    * @param \Drupal\Core\Entity\EntityInterface $decorated
    *   The decorated entity.
+   * @param array &$definitions
+   *   An array of field definitions.
    */
-  function __construct(EntityNG $decorated) {
+  function __construct(EntityNG $decorated, array &$definitions) {
     $this->decorated = $decorated;
+    $this->definitions = &$definitions;
   }
 
   /**
@@ -75,6 +85,11 @@ public function getBCEntity() {
    * Directly accesses the plain field values, as done in Drupal 7.
    */
   public function &__get($name) {
+    // Directly return the original property.
+    if ($name == 'original') {
+      return $this->decorated->values[$name];
+    }
+
     // We access the protected 'values' and 'fields' properties of the decorated
     // entity via the magic getter - which returns them by reference for us. We
     // do so, as providing references to these arrays would make $entity->values
@@ -88,7 +103,10 @@ public function &__get($name) {
       // the field objects managed by the entity, thus we need to ensure
       // $this->decorated->values reflects the latest values first.
       foreach ($this->decorated->fields[$name] as $langcode => $field) {
-        $this->decorated->values[$name][$langcode] = $field->getValue();
+        // Only set if it's not empty, otherwise there can be ghost values.
+        if (!$field->isEmpty()) {
+          $this->decorated->values[$name][$langcode] = $field->getValue();
+        }
       }
       // 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
@@ -96,21 +114,39 @@ public function &__get($name) {
       // receive the possibly updated value.
       unset($this->decorated->fields[$name]);
     }
-    // Allow accessing field values in entity default language other than
-    // LANGUAGE_DEFAULT by mapping the values to LANGUAGE_DEFAULT. This is
-    // necessary as EntityNG does key values in default language always with
-    // LANGUAGE_DEFAULT while field API expects them to be keyed by langcode.
-    $langcode = $this->decorated->language()->langcode;
-    if ($langcode != LANGUAGE_DEFAULT && isset($this->decorated->values[$name]) && is_array($this->decorated->values[$name])) {
-      if (isset($this->decorated->values[$name][LANGUAGE_DEFAULT]) && !isset($this->decorated->values[$name][$langcode])) {
-        $this->decorated->values[$name][$langcode] = &$this->decorated->values[$name][LANGUAGE_DEFAULT];
+    // When accessing values for entity properties that have been converted to
+    // an entity field, provide direct access to the plain value. This makes it
+    // possible to use the BC-decorator with properties; e.g., $node->title.
+    if (isset($this->definitions[$name]) && empty($this->definitions[$name]['configurable'])) {
+      if (!isset($this->decorated->values[$name][LANGUAGE_DEFAULT])) {
+        $this->decorated->values[$name][LANGUAGE_DEFAULT][0]['value'] = NULL;
       }
+      if (is_array($this->decorated->values[$name][LANGUAGE_DEFAULT])) {
+        // This will work with all defined properties that have a single value.
+        // We need to ensure the key doesn't matter. Mostly it's 'value' but
+        // e.g. EntityReferenceItem uses target_id.
+        if (isset($this->decorated->values[$name][LANGUAGE_DEFAULT][0]) && count($this->decorated->values[$name][LANGUAGE_DEFAULT][0]) == 1) {
+          return $this->decorated->values[$name][LANGUAGE_DEFAULT][0][key($this->decorated->values[$name][LANGUAGE_DEFAULT][0])];
+        }
+      }
+      return $this->decorated->values[$name][LANGUAGE_DEFAULT];
     }
-
-    if (!isset($this->decorated->values[$name])) {
-      $this->decorated->values[$name] = NULL;
+    else {
+      // Allow accessing field values in an entity default language other than
+      // LANGUAGE_DEFAULT by mapping the values to LANGUAGE_DEFAULT. This is
+      // necessary as EntityNG always keys default language values with
+      // LANGUAGE_DEFAULT while field API expects them to be keyed by langcode.
+      $langcode = $this->decorated->language()->langcode;
+      if ($langcode != LANGUAGE_DEFAULT && isset($this->decorated->values[$name]) && is_array($this->decorated->values[$name])) {
+        if (isset($this->decorated->values[$name][LANGUAGE_DEFAULT]) && !isset($this->decorated->values[$name][$langcode])) {
+          $this->decorated->values[$name][$langcode] = &$this->decorated->values[$name][LANGUAGE_DEFAULT];
+        }
+      }
+      if (!isset($this->decorated->values[$name])) {
+        $this->decorated->values[$name] = NULL;
+      }
+      return $this->decorated->values[$name];
     }
-    return $this->decorated->values[$name];
   }
 
   /**
@@ -119,20 +155,29 @@ public function &__get($name) {
    * Directly writes to the plain field values, as done by Drupal 7.
    */
   public function __set($name, $value) {
-    if (is_array($value) && $definition = $this->decorated->getPropertyDefinition($name)) {
-      // If field API sets a value with a langcode in entity language, move it
-      // to LANGUAGE_DEFAULT.
-      // This is necessary as EntityNG does key values in default language always
-      // with LANGUAGE_DEFAULT while field API expects them to be keyed by
-      // langcode.
-      foreach ($value as $langcode => $data) {
-        if ($langcode != LANGUAGE_DEFAULT && $langcode == $this->decorated->language()->langcode) {
-          $value[LANGUAGE_DEFAULT] = $data;
-          unset($value[$langcode]);
+    $defined = isset($this->definitions[$name]);
+    // When updating values for entity properties that have been converted to
+    // an entity field, directly write to the plain value. This makes it
+    // possible to use the BC-decorator with properties; e.g., $node->title.
+    if ($defined && empty($this->definitions[$name]['configurable'])) {
+      $this->decorated->values[$name][LANGUAGE_DEFAULT] = $value;
+    }
+    else {
+      if ($defined && is_array($value)) {
+        // If field API sets a value with a langcode in entity language, move it
+        // to LANGUAGE_DEFAULT.
+        // This is necessary as EntityNG always keys default language values
+        // with LANGUAGE_DEFAULT while field API expects them to be keyed by
+        // langcode.
+        foreach ($value as $langcode => $data) {
+          if ($langcode != LANGUAGE_DEFAULT && $langcode == $this->decorated->language()->langcode) {
+            $value[LANGUAGE_DEFAULT] = $data;
+            unset($value[$langcode]);
+          }
         }
       }
+      $this->decorated->values[$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.
@@ -151,8 +196,9 @@ public function __isset($name) {
    * Implements the magic method for unset().
    */
   public function __unset($name) {
+    // Set the value to NULL.
     $value = &$this->__get($name);
-    $value = array();
+    $value = NULL;
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Entity/EntityFormControllerNG.php b/core/lib/Drupal/Core/Entity/EntityFormControllerNG.php
index ef9bc89..b964d85 100644
--- a/core/lib/Drupal/Core/Entity/EntityFormControllerNG.php
+++ b/core/lib/Drupal/Core/Entity/EntityFormControllerNG.php
@@ -81,6 +81,11 @@ public function buildEntity(array $form, array &$form_state) {
       if (isset($definitions[$key])) {
         $translation->$key = $value;
       }
+      elseif ($entity instanceof EntityBCDecorator) {
+        // Handle yet undefined properties.
+        // @todo Remove once EntityBCDecorator is removed.
+        $entity->$key = $value;
+      }
     }
 
     // Invoke all specified builders for copying form values to entity fields.
diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php
index a0d7c03..bb614b0 100644
--- a/core/lib/Drupal/Core/Entity/EntityManager.php
+++ b/core/lib/Drupal/Core/Entity/EntityManager.php
@@ -327,4 +327,11 @@ public function getAccessController($entity_type) {
     return $this->controllers['access'][$entity_type];
   }
 
+  /**
+   * @todo: Directly allow to clear the cache in the storage controller.
+   */
+  public function resetControllers() {
+    $this->controllers = array();
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Entity/EntityNG.php b/core/lib/Drupal/Core/Entity/EntityNG.php
index 8763f6d..70ac362 100644
--- a/core/lib/Drupal/Core/Entity/EntityNG.php
+++ b/core/lib/Drupal/Core/Entity/EntityNG.php
@@ -81,6 +81,11 @@ public function __construct(array $values, $entity_type, $bundle = FALSE) {
     $this->entityType = $entity_type;
     $this->bundle = $bundle ? $bundle : $this->entityType;
     foreach ($values as $key => $value) {
+      // If the key matches an existing property set the value to the property
+      // to ensure non converted properties have the correct value.
+      if (property_exists($this, $key) && isset($value[LANGUAGE_DEFAULT])) {
+        $this->$key = $value[LANGUAGE_DEFAULT];
+      }
       $this->values[$key] = $value;
     }
     $this->init();
@@ -269,7 +274,7 @@ public function language() {
     if ($this->getPropertyDefinition('langcode')) {
       $language = $this->get('langcode')->language;
     }
-    if (!isset($language)) {
+    if (empty($language)) {
       // Make sure we return a proper language object.
       $language = new Language(array('langcode' => LANGUAGE_NOT_SPECIFIED));
     }
@@ -367,7 +372,9 @@ public function translations() {
    */
   public function getBCEntity() {
     if (!isset($this->bcEntity)) {
-      $this->bcEntity = new EntityBCDecorator($this);
+      // Initialize field definitions so that we can pass them by reference.
+      $this->getPropertyDefinitions();
+      $this->bcEntity = new EntityBCDecorator($this, $this->fieldDefinitions);
     }
     return $this->bcEntity;
   }
@@ -483,6 +490,12 @@ public function createDuplicate() {
       $uuid = new Uuid();
       $duplicate->{$entity_info['entity_keys']['uuid']}->value = $uuid->generate();
     }
+
+    // Check whether the entity type supports revisions and initialize it if so.
+    if (!empty($entity_info['entity_keys']['revision'])) {
+      $duplicate->{$entity_info['entity_keys']['revision']}->value = NULL;
+    }
+
     return $duplicate;
   }
 
diff --git a/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php b/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php
index 4159f04..62edc8d 100644
--- a/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php
+++ b/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php
@@ -37,6 +37,15 @@
   protected $properties = array();
 
   /**
+   * Holds any non-property values that get set on the object.
+   *
+   * @todo: Remove or refactor once EntityNG conversion is complete.
+   *
+   * @var array
+   */
+  protected $extraValues = array();
+
+  /**
    * Overrides ContextAwareTypedData::__construct().
    */
   public function __construct(array $definition, $name = NULL, ContextAwareInterface $parent = NULL) {
@@ -68,7 +77,7 @@ public function getValue() {
     foreach ($this->getProperties() as $name => $property) {
       $values[$name] = $property->getValue();
     }
-    return $values;
+    return $values + $this->extraValues;
   }
 
   /**
@@ -92,9 +101,11 @@ public function setValue($values) {
       else {
         $property->setValue(NULL);
       }
+      unset($values[$name]);
     }
     // @todo: Throw an exception for invalid values once conversion is
     // totally completed.
+    $this->extraValues = $values;
   }
 
   /**
@@ -129,7 +140,13 @@ public function set($property_name, $value) {
    * Implements \Drupal\Core\Entity\Field\FieldItemInterface::__get().
    */
   public function __get($name) {
-    return $this->get($name)->getValue();
+    if (isset($this->properties[$name])) {
+      return $this->properties[$name]->getValue();
+    }
+    // The property is unknown, so try to get it from the extra values.
+    elseif (isset($this->extraValues[$name])) {
+      return $this->extraValues[$name];
+    }
   }
 
   /**
@@ -140,7 +157,13 @@ public function __set($name, $value) {
     if ($value instanceof TypedDataInterface) {
       $value = $value->getValue();
     }
-    $this->get($name)->setValue($value);
+    if (isset($this->properties[$name])) {
+      $this->properties[$name]->setValue($value);
+    }
+    else {
+      // The property is unknown, so set it to the extra values.
+      $this->extraValues[$name] = $value;
+    }
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/EntityReferenceItem.php b/core/lib/Drupal/Core/Entity/Field/Type/EntityReferenceItem.php
index 496a720..bdb125b 100644
--- a/core/lib/Drupal/Core/Entity/Field/Type/EntityReferenceItem.php
+++ b/core/lib/Drupal/Core/Entity/Field/Type/EntityReferenceItem.php
@@ -86,10 +86,35 @@ public function setValue($values) {
   }
 
   /**
+   * Overrides \Drupal\Core\Entity\Field\FieldItemBase::__set().
+   */
+  public function __set($name, $value) {
+    $name = ($name == 'value') ? 'target_id' : $name;
+    parent::__set($name, $value);
+  }
+
+  /**
+   * Overrides \Drupal\Core\Entity\Field\FieldItemBase::__get().
+   */
+  public function __get($name) {
+    $name = ($name == 'value') ? 'target_id' : $name;
+    return parent::__get($name);
+  }
+
+  /**
    * Overrides \Drupal\Core\Entity\Field\FieldItemBase::get().
    */
   public function get($property_name) {
     $property_name = ($property_name == 'value') ? 'target_id' : $property_name;
     return parent::get($property_name);
   }
+
+  /**
+   * Implements \Drupal\Core\Entity\Field\FieldItemInterface::__isset().
+   */
+  public function __isset($property_name) {
+    $property_name = ($property_name == 'value') ? 'target_id' : $property_name;
+    return parent::__isset($property_name);
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/EntityWrapper.php b/core/lib/Drupal/Core/Entity/Field/Type/EntityWrapper.php
index 691868d..fdd4d38 100644
--- a/core/lib/Drupal/Core/Entity/Field/Type/EntityWrapper.php
+++ b/core/lib/Drupal/Core/Entity/Field/Type/EntityWrapper.php
@@ -54,6 +54,13 @@ class EntityWrapper extends ContextAwareTypedData implements IteratorAggregate,
   protected $id;
 
   /**
+   * If set, a new entity to create and reference.
+   *
+   * @var \Drupal\Core\Entity\EntityInterface
+   */
+  protected $newEntity;
+
+  /**
    * Overrides ContextAwareTypedData::__construct().
    */
   public function __construct(array $definition, $name = NULL, ContextAwareInterface $parent = NULL) {
@@ -65,6 +72,9 @@ public function __construct(array $definition, $name = NULL, ContextAwareInterfa
    * Overrides \Drupal\Core\TypedData\TypedData::getValue().
    */
   public function getValue() {
+    if (isset($this->newEntity)) {
+      return $this->newEntity;
+    }
     $source = $this->getIdSource();
     $id = $source ? $source->getValue() : $this->id;
     return $id ? entity_load($this->entityType, $id) : NULL;
@@ -85,10 +95,17 @@ protected function getIdSource() {
    * Both the entity ID and the entity object may be passed as value.
    */
   public function setValue($value) {
-    // Support passing in the entity object.
-    if ($value instanceof EntityInterface) {
+    // Support passing in the entity object. If it's not yet saved we have
+    // to store the whole entity such that it could be saved later on.
+    if ($value instanceof EntityInterface && $value->isNew()) {
+      $this->newEntity = $value;
+      $this->entityType = $value->entityType();
+      $value = FALSE;
+    }
+    elseif ($value instanceof EntityInterface) {
       $this->entityType = $value->entityType();
       $value = $value->id();
+      unset($this->newEntity);
     }
     elseif (isset($value) && !(is_scalar($value) && !empty($this->definition['constraints']['EntityType']))) {
       throw new InvalidArgumentException('Value is not a valid entity.');
diff --git a/core/lib/Drupal/Core/TypedData/Type/Date.php b/core/lib/Drupal/Core/TypedData/Type/Date.php
index e326674..3d72f24 100644
--- a/core/lib/Drupal/Core/TypedData/Type/Date.php
+++ b/core/lib/Drupal/Core/TypedData/Type/Date.php
@@ -24,7 +24,7 @@ class Date extends TypedData {
   /**
    * The data value.
    *
-   * @var DateTime
+   * @var \Drupal\Core\Datetime\DrupalDateTime
    */
   protected $value;
 
diff --git a/core/lib/Drupal/Core/TypedData/Type/Language.php b/core/lib/Drupal/Core/TypedData/Type/Language.php
index ac84070..2226a7e 100644
--- a/core/lib/Drupal/Core/TypedData/Type/Language.php
+++ b/core/lib/Drupal/Core/TypedData/Type/Language.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\TypedData\Type;
 
 use InvalidArgumentException;
+use Drupal\Core\Language\Language as LanguageObject;
 use Drupal\Core\TypedData\ContextAwareTypedData;
 
 /**
@@ -40,7 +41,8 @@ public function getValue() {
     $source = $this->getLanguageCodeSource();
     $langcode = $source ? $source->getValue() : $this->langcode;
     if ($langcode) {
-      return language_load($langcode);
+      $language = language_load($langcode);
+      return $language ?: new LanguageObject(array('langcode' => $this->langcode));
     }
   }
 
diff --git a/core/modules/book/book.admin.inc b/core/modules/book/book.admin.inc
index d6d369e..e4f7353 100644
--- a/core/modules/book/book.admin.inc
+++ b/core/modules/book/book.admin.inc
@@ -5,7 +5,7 @@
  * Administration page callbacks for the Book module.
  */
 
-use Drupal\node\Plugin\Core\Entity\Node;
+use Drupal\Core\Entity\EntityInterface;
 
 /**
  * Page callback: Returns an administrative overview of all books.
@@ -102,7 +102,7 @@ function book_admin_settings_submit($form, &$form_state) {
 /**
  * Form constructor for administering a single book's hierarchy.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node of the top-level page in the book.
  *
  * @see book_menu()
@@ -110,7 +110,7 @@ function book_admin_settings_submit($form, &$form_state) {
  * @see book_admin_edit_submit()
  * @ingroup forms
  */
-function book_admin_edit($form, $form_state, Node $node) {
+function book_admin_edit($form, $form_state, EntityInterface $node) {
   drupal_set_title($node->label());
   $form['#node'] = $node;
   _book_admin_table($node, $form);
@@ -183,14 +183,14 @@ function book_admin_edit_submit($form, &$form_state) {
 /**
  * Builds the table portion of the form for the book administration page.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node of the top-level page in the book.
  * @param $form
  *   The form that is being modified, passed by reference.
  *
  * @see book_admin_edit()
  */
-function _book_admin_table(Node $node, &$form) {
+function _book_admin_table(EntityInterface $node, &$form) {
   $form['table'] = array(
     '#theme' => 'book_admin_table',
     '#tree' => TRUE,
diff --git a/core/modules/book/book.module b/core/modules/book/book.module
index 81b0c99..3c5d3ce 100644
--- a/core/modules/book/book.module
+++ b/core/modules/book/book.module
@@ -5,7 +5,7 @@
  * Allows users to create and organize related content in an outline.
  */
 
-use Drupal\node\Plugin\Core\Entity\Node;
+use Drupal\Core\Entity\EntityInterface;
 use Drupal\entity\Plugin\Core\Entity\EntityDisplay;
 use Drupal\Core\Template\Attribute;
 use Drupal\menu_link\Plugin\Core\Entity\MenuLink;
@@ -89,12 +89,12 @@ function book_permission() {
 /**
  * Adds relevant book links to the node's links.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The book page node to add links to.
  * @param $view_mode
  *   The view mode of the node.
  */
-function book_node_view_link(Node $node, $view_mode) {
+function book_node_view_link(EntityInterface $node, $view_mode) {
   $links = array();
 
   if (isset($node->book['depth'])) {
@@ -201,10 +201,10 @@ function book_menu() {
 /**
  * Access callback: Determines if the book export page is accessible.
  *
- * @param \Drupal\node\Plugin\Core\Entity\Node $node
+ * @param \Drupal\node\Plugin\Core\Entity\EntityInterface $node
  *   The node whose export page is to be viewed.
  */
-function book_export_access(Node $node) {
+function book_export_access(EntityInterface $node) {
   return user_access('access printer-friendly version') && node_access('view', $node);
 }
 
@@ -215,24 +215,24 @@ function book_export_access(Node $node) {
  * - admin/content/book/%node
  * - node/%node/outline
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node whose outline tab is to be viewed.
  *
  * @see book_menu()
  */
-function _book_outline_access(Node $node) {
+function _book_outline_access(EntityInterface $node) {
   return user_access('administer book outlines') && node_access('view', $node);
 }
 
 /**
  * Access callback: Determines if the user can remove nodes from the outline.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node to remove from the outline.
  *
  * @see book_menu()
  */
-function _book_outline_remove_access(Node $node) {
+function _book_outline_remove_access(EntityInterface $node) {
   return _book_node_is_removable($node) && _book_outline_access($node);
 }
 
@@ -242,10 +242,10 @@ function _book_outline_remove_access(Node $node) {
  * A node can be removed from a book if it is actually in a book and it either
  * is not a top-level page or is a top-level page with no children.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node to remove from the outline.
  */
-function _book_node_is_removable($node) {
+function _book_node_is_removable(EntityInterface $node) {
   return (!empty($node->book['bid']) && (($node->book['bid'] != $node->nid) || !$node->book['has_children']));
 }
 
@@ -422,10 +422,10 @@ function _book_parent_select($book_link) {
 /**
  * Builds the common elements of the book form for the node and outline forms.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node whose form is being viewed.
  */
-function _book_add_form_elements(&$form, &$form_state, Node $node) {
+function _book_add_form_elements(&$form, &$form_state, EntityInterface $node) {
   // If the form is being processed during the Ajax callback of our book bid
   // dropdown, then $form_state will hold the value that was selected.
   if (isset($form_state['values']['book'])) {
@@ -525,13 +525,13 @@ function book_form_update($form, $form_state) {
  * outline through node addition, node editing, node deletion, or the outline
  * tab.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node that is being saved, added, deleted, or moved.
  *
  * @return
  *   TRUE if the menu link was saved; FALSE otherwise.
  */
-function _book_update_outline(Node $node) {
+function _book_update_outline(EntityInterface $node) {
   if (empty($node->book['bid'])) {
     return FALSE;
   }
@@ -790,7 +790,7 @@ function book_node_load($nodes, $types) {
 /**
  * Implements hook_node_view().
  */
-function book_node_view(Node $node, EntityDisplay $display, $view_mode) {
+function book_node_view(EntityInterface $node, EntityDisplay $display, $view_mode) {
   if ($view_mode == 'full') {
     if (!empty($node->book['bid']) && empty($node->in_preview)) {
       $node->content['book_navigation'] = array(
@@ -822,7 +822,7 @@ function book_page_alter(&$page) {
 /**
  * Implements hook_node_presave().
  */
-function book_node_presave(Node $node) {
+function book_node_presave(EntityInterface $node) {
   // Always save a revision for non-administrators.
   if (!empty($node->book['bid']) && !user_access('administer nodes')) {
     $node->setNewRevision();
@@ -836,7 +836,7 @@ function book_node_presave(Node $node) {
 /**
  * Implements hook_node_insert().
  */
-function book_node_insert(Node $node) {
+function book_node_insert(EntityInterface $node) {
   if (!empty($node->book['bid'])) {
     if ($node->book['bid'] == 'new') {
       // New nodes that are their own book.
@@ -851,7 +851,7 @@ function book_node_insert(Node $node) {
 /**
  * Implements hook_node_update().
  */
-function book_node_update(Node $node) {
+function book_node_update(EntityInterface $node) {
   if (!empty($node->book['bid'])) {
     if ($node->book['bid'] == 'new') {
       // New nodes that are their own book.
@@ -866,7 +866,7 @@ function book_node_update(Node $node) {
 /**
  * Implements hook_node_predelete().
  */
-function book_node_predelete(Node $node) {
+function book_node_predelete(EntityInterface $node) {
   if (!empty($node->book['bid'])) {
     if ($node->nid == $node->book['bid']) {
       // Handle deletion of a top-level post.
@@ -890,7 +890,7 @@ function book_node_predelete(Node $node) {
 /**
  * Implements hook_node_prepare().
  */
-function book_node_prepare(Node $node) {
+function book_node_prepare(EntityInterface $node) {
   // Prepare defaults for the add/edit form.
   if (empty($node->book) && (user_access('add content to books') || user_access('administer book outlines'))) {
     $node->book = array();
@@ -1186,7 +1186,7 @@ function book_export_traverse($tree, $visit_func) {
 /**
  * Generates printer-friendly HTML for a node.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node that will be output.
  * @param $children
  *   (optional) All the rendered child nodes within the current node. Defaults
@@ -1197,7 +1197,7 @@ function book_export_traverse($tree, $visit_func) {
  *
  * @see book_export_traverse()
  */
-function book_node_export(Node $node, $children = '') {
+function book_node_export(EntityInterface $node, $children = '') {
   $build = node_view($node, 'print');
   unset($build['#theme']);
   // @todo Rendering should happen in the template using render().
diff --git a/core/modules/book/book.pages.inc b/core/modules/book/book.pages.inc
index a971aa6..2418591 100644
--- a/core/modules/book/book.pages.inc
+++ b/core/modules/book/book.pages.inc
@@ -5,7 +5,7 @@
  * User page callbacks for the book module.
  */
 
-use Drupal\node\Plugin\Core\Entity\Node;
+use Drupal\Core\Entity\EntityInterface;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 
@@ -39,7 +39,7 @@ function book_render() {
  *   currently supported in book module:
  *   - html: Printer-friendly HTML.
  *   Other types may be supported in contributed modules.
- * @param \Drupal\node\Plugin\Core\Entity\Node $node
+ * @param \Drupal\node\Plugin\Core\Entity\EntityInterface $node
  *   The node to export.
  *
  * @return
@@ -50,7 +50,7 @@ function book_render() {
  *
  * @see book_menu()
  */
-function book_export($type, Node $node) {
+function book_export($type, EntityInterface $node) {
   $type = drupal_strtolower($type);
 
   $export_function = 'book_export_' . $type;
@@ -84,7 +84,7 @@ function book_export($type, Node $node) {
  * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
  * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
  */
-function book_export_html(Node $node) {
+function book_export_html(EntityInterface $node) {
   if (user_access('access printer-friendly version')) {
     if (isset($node->book)) {
       $tree = book_menu_subtree_data($node->book);
@@ -103,7 +103,7 @@ function book_export_html(Node $node) {
 /**
  * Page callback: Shows the outline form for a single node.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The book node for which to show the outline.
  *
  * @return string
@@ -111,7 +111,7 @@ function book_export_html(Node $node) {
  *
  * @see book_menu()
  */
-function book_outline(Node $node) {
+function book_outline(EntityInterface $node) {
   drupal_set_title($node->label());
   return drupal_get_form('book_outline_form', $node);
 }
@@ -121,14 +121,14 @@ function book_outline(Node $node) {
  *
  * Allows handling of all book outline operations via the outline tab.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The book node for which to show the outline.
  *
  * @see book_outline_form_submit()
  * @see book_remove_button_submit()
  * @ingroup forms
  */
-function book_outline_form($form, &$form_state, Node $node) {
+function book_outline_form($form, &$form_state, EntityInterface $node) {
   if (!isset($node->book)) {
     // The node is not part of any book yet - set default options.
     $node->book = _book_link_defaults($node->nid);
@@ -208,14 +208,14 @@ function book_outline_form_submit($form, &$form_state) {
 /**
  * Form constructor to confirm removal of a node from a book.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node to delete.
  *
  * @see book_remove_form_submit()
  * @see book_menu()
  * @ingroup forms
  */
-function book_remove_form($form, &$form_state, Node $node) {
+function book_remove_form($form, &$form_state, EntityInterface $node) {
   $form['#node'] = $node;
   $title = array('%title' => $node->label());
 
diff --git a/core/modules/book/lib/Drupal/book/Tests/BookTest.php b/core/modules/book/lib/Drupal/book/Tests/BookTest.php
index 4798cee..01d18de 100644
--- a/core/modules/book/lib/Drupal/book/Tests/BookTest.php
+++ b/core/modules/book/lib/Drupal/book/Tests/BookTest.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\book\Tests;
 
-use Drupal\node\Plugin\Core\Entity\Node;
+use Drupal\Core\Entity\EntityInterface;
 use Drupal\simpletest\WebTestBase;
 
 /**
@@ -145,7 +145,7 @@ function testBook() {
    *
    * Also checks the printer friendly version of the outline.
    *
-   * @param Drupal\node\Node $node
+   * @param \Drupal\Core\Entity\EntityInterface $node
    *   Node to check.
    * @param $nodes
    *   Nodes that should be in outline.
@@ -158,7 +158,7 @@ function testBook() {
    * @param array $breadcrumb
    *   The nodes that should be displayed in the breadcrumb.
    */
-  function checkBookNode(Node $node, $nodes, $previous = FALSE, $up = FALSE, $next = FALSE, array $breadcrumb) {
+  function checkBookNode(EntityInterface $node, $nodes, $previous = FALSE, $up = FALSE, $next = FALSE, array $breadcrumb) {
     // $number does not use drupal_static as it should not be reset
     // since it uniquely identifies each call to checkBookNode().
     static $number = 0;
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index 9ee6f81..dd87b29 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -9,7 +9,6 @@
  * book page, etc.
  */
 
-use Drupal\node\Plugin\Core\Entity\Node;
 use Drupal\entity\Plugin\Core\Entity\EntityDisplay;
 use Drupal\file\Plugin\Core\Entity\File;
 use Drupal\Core\Entity\EntityInterface;
@@ -491,13 +490,13 @@ function comment_get_recent($number = 10) {
  *   Number of comments.
  * @param $new_replies
  *   Number of new replies.
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The first new comment node.
  *
  * @return
  *   "page=X" if the page number is greater than zero; empty string otherwise.
  */
-function comment_new_page_count($num_comments, $new_replies, Node $node) {
+function comment_new_page_count($num_comments, $new_replies, EntityInterface $node) {
   $mode = variable_get('comment_default_mode_' . $node->type, COMMENT_MODE_THREADED);
   $comments_per_page = variable_get('comment_default_per_page_' . $node->type, 50);
   $pagenum = NULL;
@@ -575,7 +574,7 @@ function theme_comment_block($variables) {
 /**
  * Implements hook_node_view().
  */
-function comment_node_view(Node $node, EntityDisplay $display, $view_mode) {
+function comment_node_view(EntityInterface $node, EntityDisplay $display, $view_mode) {
   $links = array();
 
   if ($node->comment != COMMENT_NODE_HIDDEN) {
@@ -683,14 +682,14 @@ function comment_node_view(Node $node, EntityDisplay $display, $view_mode) {
 /**
  * Builds the comment-related elements for node detail pages.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node entity for which to build the comment-related elements.
  *
  * @return
  *   A renderable array representing the comment-related page elements for the
  *   node.
  */
-function comment_node_page_additions(Node $node) {
+function comment_node_page_additions(EntityInterface $node) {
   $additions = array();
 
   // Only attempt to render comments if the node has visible comments.
@@ -728,7 +727,7 @@ function comment_node_page_additions(Node $node) {
 /**
  * Returns a rendered form to comment the given node.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node entity to be commented.
  * @param int $pid
  *   (optional) Some comments are replies to other comments. In those cases,
@@ -737,7 +736,7 @@ function comment_node_page_additions(Node $node) {
  * @return array
  *   The renderable array for the comment addition form.
  */
-function comment_add(Node $node, $pid = NULL) {
+function comment_add(EntityInterface $node, $pid = NULL) {
   $values = array('nid' => $node->nid, 'pid' => $pid, 'node_type' => 'comment_node_' . $node->type);
   $comment = entity_create('comment', $values);
   return entity_get_form($comment);
@@ -746,7 +745,7 @@ function comment_add(Node $node, $pid = NULL) {
 /**
  * Retrieves comments for a thread.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node whose comment(s) needs rendering.
  * @param $mode
  *   The comment display mode; COMMENT_MODE_FLAT or COMMENT_MODE_THREADED.
@@ -810,7 +809,7 @@ function comment_add(Node $node, $pid = NULL) {
  * spoil the reverse ordering, "ORDER BY thread ASC" -- here, we do not need
  * to consider the trailing "/" so we use a substring only.
  */
-function comment_get_thread(Node $node, $mode, $comments_per_page) {
+function comment_get_thread(EntityInterface $node, $mode, $comments_per_page) {
   $query = db_select('comment', 'c')
     ->extend('Drupal\Core\Database\Query\PagerSelectExtender');
   $query->addField('c', 'cid');
@@ -920,13 +919,13 @@ function comment_view(Comment $comment, $view_mode = 'full', $langcode = NULL) {
  *
  * @param Drupal\comment\Comment $comment
  *   The comment object.
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node the comment is attached to.
  *
  * @return
  *   A structured array of links.
  */
-function comment_links(Comment $comment, Node $node) {
+function comment_links(Comment $comment, EntityInterface $node) {
   $links = array();
   if ($node->comment == COMMENT_NODE_OPEN) {
     if (user_access('administer comments') && user_access('post comments')) {
@@ -1200,7 +1199,7 @@ function comment_node_load($nodes, $types) {
 /**
  * Implements hook_node_prepare().
  */
-function comment_node_prepare(Node $node) {
+function comment_node_prepare(EntityInterface $node) {
   if (!isset($node->comment)) {
     $node->comment = variable_get("comment_$node->type", COMMENT_NODE_OPEN);
   }
@@ -1209,7 +1208,7 @@ function comment_node_prepare(Node $node) {
 /**
  * Implements hook_node_insert().
  */
-function comment_node_insert(Node $node) {
+function comment_node_insert(EntityInterface $node) {
   // Allow bulk updates and inserts to temporarily disable the
   // maintenance of the {node_comment_statistics} table.
   if (variable_get('comment_maintain_node_statistics', TRUE)) {
@@ -1229,7 +1228,7 @@ function comment_node_insert(Node $node) {
 /**
  * Implements hook_node_predelete().
  */
-function comment_node_predelete(Node $node) {
+function comment_node_predelete(EntityInterface $node) {
   $cids = db_query('SELECT cid FROM {comment} WHERE nid = :nid', array(':nid' => $node->nid))->fetchCol();
   comment_delete_multiple($cids);
   db_delete('node_comment_statistics')
@@ -1240,7 +1239,7 @@ function comment_node_predelete(Node $node) {
 /**
  * Implements hook_node_update_index().
  */
-function comment_node_update_index(Node $node, $langcode) {
+function comment_node_update_index(EntityInterface $node, $langcode) {
   $index_comments = &drupal_static(__FUNCTION__);
 
   if ($index_comments === NULL) {
@@ -1289,7 +1288,7 @@ function comment_update_index() {
  * Formats a comment count string and returns it, for display with search
  * results.
  */
-function comment_node_search_result(Node $node) {
+function comment_node_search_result(EntityInterface $node) {
   // Do not make a string if comments are hidden.
   if (user_access('access comments') && $node->comment != COMMENT_NODE_HIDDEN) {
     $comments = db_query('SELECT comment_count FROM {node_comment_statistics} WHERE nid = :nid', array('nid' => $node->nid))->fetchField();
diff --git a/core/modules/comment/comment.pages.inc b/core/modules/comment/comment.pages.inc
index da359a4..be4ef3f 100644
--- a/core/modules/comment/comment.pages.inc
+++ b/core/modules/comment/comment.pages.inc
@@ -5,7 +5,7 @@
  * User page callbacks for the Comment module.
  */
 
-use Drupal\node\Plugin\Core\Entity\Node;
+use Drupal\Core\Entity\EntityInterface;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 
@@ -21,7 +21,7 @@
  * The node or comment that is being replied to must appear above the comment
  * form to provide the user context while authoring the comment.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   Every comment belongs to a node. This is that node.
  * @param $pid
  *   (optional) Some comments are replies to other comments. In those cases,
@@ -34,7 +34,7 @@
  *     - comment_parent: If the comment is a reply to another comment.
  *   - comment_form: The comment form as a renderable array.
  */
-function comment_reply(Node $node, $pid = NULL) {
+function comment_reply(EntityInterface $node, $pid = NULL) {
   // Set the breadcrumb trail.
   drupal_set_breadcrumb(array(l(t('Home'), NULL), l($node->label(), 'node/' . $node->nid)));
   $op = isset($_POST['op']) ? $_POST['op'] : '';
diff --git a/core/modules/comment/lib/Drupal/comment/CommentStorageController.php b/core/modules/comment/lib/Drupal/comment/CommentStorageController.php
index 274b37b..77e441f 100644
--- a/core/modules/comment/lib/Drupal/comment/CommentStorageController.php
+++ b/core/modules/comment/lib/Drupal/comment/CommentStorageController.php
@@ -56,7 +56,7 @@ protected function attachLoad(&$records, $load_revision = FALSE) {
    */
   public function create(array $values) {
     if (empty($values['node_type']) && !empty($values['nid'])) {
-      $node = node_load($values['nid']);
+      $node = node_load(is_object($values['nid']) ? $values['nid']->value : $values['nid']);
       $values['node_type'] = 'comment_node_' . $node->type;
     }
     return parent::create($values);
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php
index e49f2f3..c023c56 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php
@@ -80,7 +80,7 @@ function setUp() {
   /**
    * Posts a comment.
    *
-   * @param Drupal\node\Node|null $node
+   * @param \Drupal\Core\Entity\EntityInterface $node|null $node
    *   Node to post comment on or NULL to post to the previusly loaded page.
    * @param $comment
    *   Comment body.
diff --git a/core/modules/datetime/lib/Drupal/datetime/Tests/DateTimeFieldTest.php b/core/modules/datetime/lib/Drupal/datetime/Tests/DateTimeFieldTest.php
deleted file mode 100644
index 232d019..0000000
--- a/core/modules/datetime/lib/Drupal/datetime/Tests/DateTimeFieldTest.php
+++ /dev/null
@@ -1,428 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\datetime\Tests\DatetimeFieldTest.
- */
-
-namespace Drupal\datetime\Tests;
-
-use Drupal\simpletest\WebTestBase;
-use Drupal\Core\Datetime\DrupalDateTime;
-
-/**
- * Tests Datetime field functionality.
- */
-class DatetimeFieldTest extends WebTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = array('node', 'field_test', 'datetime', 'field_ui');
-
-  /**
-   * A field to use in this test class.
-   *
-   * @var \Drupal\Core\Datetime\DrupalDateTime
-   */
-  protected $field;
-
-  public static function getInfo() {
-    return array(
-      'name'  => 'Datetime Field',
-      'description'  => 'Tests datetime field functionality.',
-      'group' => 'Datetime',
-    );
-  }
-
-  function setUp() {
-    parent::setUp();
-
-    $web_user = $this->drupalCreateUser(array(
-      'access field_test content',
-      'administer field_test content',
-      'administer content types',
-    ));
-    $this->drupalLogin($web_user);
-
-    // Create a field with settings to validate.
-    $this->field = array(
-      'field_name' => drupal_strtolower($this->randomName()),
-      'type' => 'datetime',
-      'settings' => array('datetime_type' => 'date'),
-    );
-    field_create_field($this->field);
-    $this->instance = array(
-      'field_name' => $this->field['field_name'],
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle',
-      'widget' => array(
-        'type' => 'datetime_default',
-      ),
-      'settings' => array(
-        'default_value' => 'blank',
-      ),
-    );
-    field_create_instance($this->instance);
-
-    $this->display_options = array(
-      'type' => 'datetime_default',
-      'label' => 'hidden',
-      'settings' => array('format_type' => 'medium'),
-    );
-    entity_get_display($this->instance['entity_type'], $this->instance['bundle'], 'full')
-      ->setComponent($this->field['field_name'], $this->display_options)
-      ->save();
-  }
-
-  /**
-   * Tests date field functionality.
-   */
-  function testDateField() {
-
-    // Display creation form.
-    $this->drupalGet('test-entity/add/test_bundle');
-    $langcode = LANGUAGE_NOT_SPECIFIED;
-    $this->assertFieldByName("{$this->field['field_name']}[$langcode][0][value][date]", '', 'Date element found.');
-    $this->assertNoFieldByName("{$this->field['field_name']}[$langcode][0][value][time]", '', 'Time element not found.');
-
-    // Submit a valid date and ensure it is accepted.
-    $value = '2012-12-31 00:00:00';
-    $date = new DrupalDateTime($value);
-    $format_type = $date->canUseIntl() ? DrupalDateTime::INTL : DrupalDateTime::PHP;
-    $date_format = config('system.date')->get('formats.html_date.pattern.' . $format_type);
-    $time_format = config('system.date')->get('formats.html_time.pattern.' . $format_type);
-
-    $edit = array(
-      "{$this->field['field_name']}[$langcode][0][value][date]" => $date->format($date_format),
-    );
-    $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
-    $id = $match[1];
-    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)));
-    $this->assertRaw($date->format($date_format));
-    $this->assertNoRaw($date->format($time_format));
-
-    // The expected values will use the default time.
-    datetime_date_default_time($date);
-
-    // Verify that the date is output according to the formatter settings.
-    $options = array(
-      'format_type' => array('short', 'medium', 'long'),
-    );
-    foreach ($options as $setting => $values) {
-      foreach ($values as $new_value) {
-        // Update the entity display settings.
-        $this->display_options['settings'] = array($setting => $new_value);
-        $display = entity_get_display($this->instance['entity_type'], $this->instance['bundle'], 'full')
-          ->setComponent($this->instance['field_name'], $this->display_options)
-          ->save();
-
-        $this->renderTestEntity($id);
-        switch ($setting) {
-          case 'format_type':
-            // Verify that a date is displayed.
-            $expected = format_date($date->getTimestamp(), $new_value);
-            $this->renderTestEntity($id);
-            $this->assertText($expected, format_string('Formatted date field using %value format displayed as %expected.', array('%value' => $new_value, '%expected' => $expected)));
-            break;
-        }
-      }
-    }
-
-    // Verify that the plain formatter works.
-    $this->display_options['type'] = 'datetime_plain';
-    $display = entity_get_display($this->instance['entity_type'], $this->instance['bundle'], 'full')
-      ->setComponent($this->instance['field_name'], $this->display_options)
-      ->save();
-    $expected = $date->format(DATETIME_DATE_STORAGE_FORMAT);
-    $this->renderTestEntity($id);
-    $this->assertText($expected, format_string('Formatted date field using plain format displayed as %expected.', array('%expected' => $expected)));
-  }
-
-  /**
-   * Tests date and time field.
-   */
-  function testDatetimeField() {
-
-    // Change the field to a datetime field.
-    $this->field['settings']['datetime_type'] = 'datetime';
-    field_update_field($this->field);
-
-    // Display creation form.
-    $this->drupalGet('test-entity/add/test_bundle');
-    $langcode = LANGUAGE_NOT_SPECIFIED;
-    $this->assertFieldByName("{$this->field['field_name']}[$langcode][0][value][date]", '', 'Date element found.');
-    $this->assertFieldByName("{$this->field['field_name']}[$langcode][0][value][time]", '', 'Time element found.');
-
-    // Submit a valid date and ensure it is accepted.
-    $value = '2012-12-31 00:00:00';
-    $date = new DrupalDateTime($value);
-    $format_type = $date->canUseIntl() ? DrupalDateTime::INTL : DrupalDateTime::PHP;
-    $date_format = config('system.date')->get('formats.html_date.pattern.' . $format_type);
-    $time_format = config('system.date')->get('formats.html_time.pattern.' . $format_type);
-
-    $edit = array(
-      "{$this->field['field_name']}[$langcode][0][value][date]" => $date->format($date_format),
-      "{$this->field['field_name']}[$langcode][0][value][time]" => $date->format($time_format),
-    );
-    $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
-    $id = $match[1];
-    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)));
-    $this->assertRaw($date->format($date_format));
-    $this->assertRaw($date->format($time_format));
-
-    // Verify that the date is output according to the formatter settings.
-    $options = array(
-      'format_type' => array('short', 'medium', 'long'),
-    );
-    foreach ($options as $setting => $values) {
-      foreach ($values as $new_value) {
-        // Update the entity display settings.
-        $this->display_options['settings'] = array($setting => $new_value);
-        $display = entity_get_display($this->instance['entity_type'], $this->instance['bundle'], 'full')
-          ->setComponent($this->instance['field_name'], $this->display_options)
-          ->save();
-
-        $this->renderTestEntity($id);
-        switch ($setting) {
-          case 'format_type':
-            // Verify that a date is displayed.
-            $expected = format_date($date->getTimestamp(), $new_value);
-            $this->renderTestEntity($id);
-            $this->assertText($expected, format_string('Formatted date field using %value format displayed as %expected.', array('%value' => $new_value, '%expected' => $expected)));
-            break;
-        }
-      }
-    }
-
-    // Verify that the plain formatter works.
-    $this->display_options['type'] = 'datetime_plain';
-    $display = entity_get_display($this->instance['entity_type'], $this->instance['bundle'], 'full')
-      ->setComponent($this->instance['field_name'], $this->display_options)
-      ->save();
-    $expected = $date->format(DATETIME_DATETIME_STORAGE_FORMAT);
-    $this->renderTestEntity($id);
-    $this->assertText($expected, format_string('Formatted date field using plain format displayed as %expected.', array('%expected' => $expected)));
-  }
-
-  /**
-   * Tests Date List Widget functionality.
-   */
-  function testDatelistWidget() {
-
-    // Change the field to a datetime field.
-    $this->field['settings']['datetime_type'] = 'datetime';
-    field_update_field($this->field);
-
-    // Change the widget to a datelist widget.
-    $increment = 1;
-    $date_order = 'YMD';
-    $time_type = '12';
-
-    $this->instance['widget']['type'] = 'datetime_datelist';
-    $this->instance['widget']['settings'] = array(
-      'increment' => $increment,
-      'date_order' => $date_order,
-      'time_type' => $time_type,
-    );
-    field_update_instance($this->instance);
-    field_cache_clear();
-
-    // Display creation form.
-    $this->drupalGet('test-entity/add/test_bundle');
-    $field_name = $this->field['field_name'];
-    $langcode = LANGUAGE_NOT_SPECIFIED;
-
-    $this->assertFieldByXPath("//*[@id=\"edit-$field_name-$langcode-0-value-year\"]", NULL, 'Year element found.');
-    $this->assertOptionSelected("edit-$field_name-$langcode-0-value-year", '', 'No year selected.');
-    $this->assertFieldByXPath("//*[@id=\"edit-$field_name-$langcode-0-value-month\"]", NULL, 'Month element found.');
-    $this->assertOptionSelected("edit-$field_name-$langcode-0-value-month", '', 'No month selected.');
-    $this->assertFieldByXPath("//*[@id=\"edit-$field_name-$langcode-0-value-day\"]", NULL, 'Day element found.');
-    $this->assertOptionSelected("edit-$field_name-$langcode-0-value-day", '', 'No day selected.');
-    $this->assertFieldByXPath("//*[@id=\"edit-$field_name-$langcode-0-value-hour\"]", NULL, 'Hour element found.');
-    $this->assertOptionSelected("edit-$field_name-$langcode-0-value-hour", '', 'No hour selected.');
-    $this->assertFieldByXPath("//*[@id=\"edit-$field_name-$langcode-0-value-minute\"]", NULL, 'Minute element found.');
-    $this->assertOptionSelected("edit-$field_name-$langcode-0-value-minute", '', 'No minute selected.');
-    $this->assertNoFieldByXPath("//*[@id=\"edit-$field_name-$langcode-0-value-second\"]", NULL, 'Second element not found.');
-    $this->assertFieldByXPath("//*[@id=\"edit-$field_name-$langcode-0-value-ampm\"]", NULL, 'AMPM element found.');
-    $this->assertOptionSelected("edit-$field_name-$langcode-0-value-ampm", '', 'No ampm selected.');
-
-    // Submit a valid date and ensure it is accepted.
-    $date_value = array('year' => 2012, 'month' => 12, 'day' => 31, 'hour' => 5, 'minute' => 15);
-    $date = new DrupalDateTime($date_value);
-
-    $edit = array();
-    // Add the ampm indicator since we are testing 12 hour time.
-    $date_value['ampm'] = 'am';
-    foreach ($date_value as $part => $value) {
-      $edit["{$this->field['field_name']}[$langcode][0][value][$part]"] = $value;
-    }
-
-    $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
-    $id = $match[1];
-    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)));
-
-    $this->assertOptionSelected("edit-$field_name-$langcode-0-value-year", '2012', 'Correct year selected.');
-    $this->assertOptionSelected("edit-$field_name-$langcode-0-value-month", '12', 'Correct month selected.');
-    $this->assertOptionSelected("edit-$field_name-$langcode-0-value-day", '31', 'Correct day selected.');
-    $this->assertOptionSelected("edit-$field_name-$langcode-0-value-hour", '5', 'Correct hour selected.');
-    $this->assertOptionSelected("edit-$field_name-$langcode-0-value-minute", '15', 'Correct minute selected.');
-    $this->assertOptionSelected("edit-$field_name-$langcode-0-value-ampm", 'am', 'Correct ampm selected.');
-  }
-
-  /**
-   * Test default value functionality.
-   */
-  function testDefaultValue() {
-
-    // Change the field to a datetime field.
-    $this->field['settings']['datetime_type'] = 'datetime';
-    field_update_field($this->field);
-
-    // Set the default value to 'now'.
-    $this->instance['settings']['default_value'] = 'now';
-    $this->instance['default_value_function'] = 'datetime_default_value';
-    field_update_instance($this->instance);
-
-    // Display creation form.
-    $date = new DrupalDateTime();
-    $date_format = 'Y-m-d';
-    $this->drupalGet('test-entity/add/test_bundle');
-    $langcode = LANGUAGE_NOT_SPECIFIED;
-
-    // See if current date is set. We cannot test for the precise time because
-    // it may be a few seconds between the time the comparison date is created
-    // and the form date, so we just test the date and that the time is not
-    // empty.
-    $this->assertFieldByName("{$this->field['field_name']}[$langcode][0][value][date]", $date->format($date_format), 'Date element found.');
-    $this->assertNoFieldByName("{$this->field['field_name']}[$langcode][0][value][time]", '', 'Time element found.');
-
-    // Set the default value to 'blank'.
-    $this->instance['settings']['default_value'] = 'blank';
-    field_update_instance($this->instance);
-
-    // Display creation form.
-    $date = new DrupalDateTime();
-    $this->drupalGet('test-entity/add/test_bundle');
-
-    // See that no date is set.
-    $this->assertFieldByName("{$this->field['field_name']}[$langcode][0][value][date]", '', 'Date element found.');
-    $this->assertFieldByName("{$this->field['field_name']}[$langcode][0][value][time]", '', 'Time element found.');
-  }
-
-  /**
-   * Test that invalid values are caught and marked as invalid.
-   */
-  function testInvalidField() {
-
-    // Change the field to a datetime field.
-    $this->field['settings']['datetime_type'] = 'datetime';
-    field_update_field($this->field);
-
-    // Display creation form.
-    $this->drupalGet('test-entity/add/test_bundle');
-    $langcode = LANGUAGE_NOT_SPECIFIED;
-    $this->assertFieldByName("{$this->field['field_name']}[$langcode][0][value][date]", '', 'Date element found.');
-    $this->assertFieldByName("{$this->field['field_name']}[$langcode][0][value][time]", '', 'Time element found.');
-
-    // Submit invalid dates and ensure they is not accepted.
-    $date_value = '';
-    $edit = array(
-      "{$this->field['field_name']}[$langcode][0][value][date]" => $date_value,
-      "{$this->field['field_name']}[$langcode][0][value][time]" => '12:00:00',
-    );
-    $this->drupalPost(NULL, $edit, t('Save'));
-    $this->assertText('date is invalid', 'Empty date value has been caught.');
-
-    $date_value = 'aaaa-12-01';
-    $edit = array(
-      "{$this->field['field_name']}[$langcode][0][value][date]" => $date_value,
-      "{$this->field['field_name']}[$langcode][0][value][time]" => '00:00:00',
-    );
-    $this->drupalPost(NULL, $edit, t('Save'));
-    $this->assertText('date is invalid', format_string('Invalid year value %date has been caught.', array('%date' => $date_value)));
-
-    $date_value = '2012-75-01';
-    $edit = array(
-      "{$this->field['field_name']}[$langcode][0][value][date]" => $date_value,
-      "{$this->field['field_name']}[$langcode][0][value][time]" => '00:00:00',
-    );
-    $this->drupalPost(NULL, $edit, t('Save'));
-    $this->assertText('date is invalid', format_string('Invalid month value %date has been caught.', array('%date' => $date_value)));
-
-    $date_value = '2012-12-99';
-    $edit = array(
-      "{$this->field['field_name']}[$langcode][0][value][date]" => $date_value,
-      "{$this->field['field_name']}[$langcode][0][value][time]" => '00:00:00',
-    );
-    $this->drupalPost(NULL, $edit, t('Save'));
-    $this->assertText('date is invalid', format_string('Invalid day value %date has been caught.', array('%date' => $date_value)));
-
-    $date_value = '2012-12-01';
-    $time_value = '';
-    $edit = array(
-      "{$this->field['field_name']}[$langcode][0][value][date]" => $date_value,
-      "{$this->field['field_name']}[$langcode][0][value][time]" => $time_value,
-    );
-    $this->drupalPost(NULL, $edit, t('Save'));
-    $this->assertText('date is invalid', 'Empty time value has been caught.');
-
-    $date_value = '2012-12-01';
-    $time_value = '49:00:00';
-    $edit = array(
-      "{$this->field['field_name']}[$langcode][0][value][date]" => $date_value,
-      "{$this->field['field_name']}[$langcode][0][value][time]" => $time_value,
-    );
-    $this->drupalPost(NULL, $edit, t('Save'));
-    $this->assertText('date is invalid', format_string('Invalid hour value %time has been caught.', array('%time' => $time_value)));
-
-    $date_value = '2012-12-01';
-    $time_value = '12:99:00';
-    $edit = array(
-      "{$this->field['field_name']}[$langcode][0][value][date]" => $date_value,
-      "{$this->field['field_name']}[$langcode][0][value][time]" => $time_value,
-    );
-    $this->drupalPost(NULL, $edit, t('Save'));
-    $this->assertText('date is invalid', format_string('Invalid minute value %time has been caught.', array('%time' => $time_value)));
-
-    $date_value = '2012-12-01';
-    $time_value = '12:15:99';
-    $edit = array(
-      "{$this->field['field_name']}[$langcode][0][value][date]" => $date_value,
-      "{$this->field['field_name']}[$langcode][0][value][time]" => $time_value,
-    );
-    $this->drupalPost(NULL, $edit, t('Save'));
-    $this->assertText('date is invalid', format_string('Invalid second value %time has been caught.', array('%time' => $time_value)));
-  }
-
-  /**
-   * Renders a test_entity and sets the output in the internal browser.
-   *
-   * @param int $id
-   *   The test_entity ID to render.
-   * @param string $view_mode
-   *   (optional) The view mode to use for rendering. Defaults to 'full'.
-   * @param bool $reset
-   *   (optional) Whether to reset the test_entity controller cache. Defaults to
-   *   TRUE to simplify testing.
-   */
-  protected function renderTestEntity($id, $view_mode = 'full', $reset = TRUE) {
-    if ($reset) {
-      entity_get_controller('test_entity')->resetCache(array($id));
-    }
-    $entity = field_test_entity_test_load($id);
-    $display = entity_get_display('test_entity', $entity->bundle(), 'full');
-    field_attach_prepare_view('test_entity', array($entity->id() => $entity), array($entity->bundle() => $display), $view_mode);
-    $entity->content = field_attach_view($entity, $display, $view_mode);
-
-    $output = drupal_render($entity->content);
-    $this->drupalSetContent($output);
-    $this->verbose($output);
-  }
-
-}
diff --git a/core/modules/datetime/lib/Drupal/datetime/Tests/DatetimeFieldTest.php b/core/modules/datetime/lib/Drupal/datetime/Tests/DatetimeFieldTest.php
new file mode 100644
index 0000000..968f062
--- /dev/null
+++ b/core/modules/datetime/lib/Drupal/datetime/Tests/DatetimeFieldTest.php
@@ -0,0 +1,435 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\datetime\Tests\DatetimeFieldTest.
+ */
+
+namespace Drupal\datetime\Tests;
+
+use Drupal\simpletest\WebTestBase;
+use Drupal\Core\Datetime\DrupalDateTime;
+
+/**
+ * Tests Datetime field functionality.
+ */
+class DatetimeFieldTest extends WebTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('node', 'field_test', 'datetime', 'field_ui', 'entity_test');
+
+  /**
+   * A field to use in this test class.
+   *
+   * @var \Drupal\Core\Datetime\DrupalDateTime
+   */
+  protected $field;
+
+  public static function getInfo() {
+    return array(
+      'name'  => 'Datetime Field',
+      'description'  => 'Tests datetime field functionality.',
+      'group' => 'Datetime',
+    );
+  }
+
+  function setUp() {
+    parent::setUp();
+
+    $web_user = $this->drupalCreateUser(array(
+      'view test entity',
+      'administer entity_test content',
+      'administer content types',
+    ));
+    $this->drupalLogin($web_user);
+
+    // Create a field with settings to validate.
+    $this->field = array(
+      'field_name' => drupal_strtolower($this->randomName()),
+      'type' => 'datetime',
+      'settings' => array('datetime_type' => 'date'),
+    );
+    field_create_field($this->field);
+    $this->instance = array(
+      'field_name' => $this->field['field_name'],
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
+      'widget' => array(
+        'type' => 'datetime_default',
+      ),
+      'settings' => array(
+        'default_value' => 'blank',
+      ),
+    );
+    field_create_instance($this->instance);
+
+    $this->display_options = array(
+      'type' => 'datetime_default',
+      'label' => 'hidden',
+      'settings' => array('format_type' => 'medium'),
+    );
+    entity_get_display($this->instance['entity_type'], $this->instance['bundle'], 'full')
+      ->setComponent($this->field['field_name'], $this->display_options)
+      ->save();
+  }
+
+  /**
+   * Tests date field functionality.
+   */
+  function testDateField() {
+
+    // Display creation form.
+    $this->drupalGet('entity_test/add');
+    $langcode = LANGUAGE_NOT_SPECIFIED;
+    $this->assertFieldByName("{$this->field['field_name']}[$langcode][0][value][date]", '', 'Date element found.');
+    $this->assertNoFieldByName("{$this->field['field_name']}[$langcode][0][value][time]", '', 'Time element not found.');
+
+    // Submit a valid date and ensure it is accepted.
+    $value = '2012-12-31 00:00:00';
+    $date = new DrupalDateTime($value);
+    $format_type = $date->canUseIntl() ? DrupalDateTime::INTL : DrupalDateTime::PHP;
+    $date_format = config('system.date')->get('formats.html_date.pattern.' . $format_type);
+    $time_format = config('system.date')->get('formats.html_time.pattern.' . $format_type);
+
+    $edit = array(
+      'user_id' => 1,
+      'name' => $this->randomName(),
+      "{$this->field['field_name']}[$langcode][0][value][date]" => $date->format($date_format),
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+    preg_match('|entity_test/manage/(\d+)/edit|', $this->url, $match);
+    $id = $match[1];
+    $this->assertText(t('entity_test @id has been created.', array('@id' => $id)));
+    $this->assertRaw($date->format($date_format));
+    $this->assertNoRaw($date->format($time_format));
+
+    // The expected values will use the default time.
+    datetime_date_default_time($date);
+
+    // Verify that the date is output according to the formatter settings.
+    $options = array(
+      'format_type' => array('short', 'medium', 'long'),
+    );
+    foreach ($options as $setting => $values) {
+      foreach ($values as $new_value) {
+        // Update the entity display settings.
+        $this->display_options['settings'] = array($setting => $new_value);
+        $display = entity_get_display($this->instance['entity_type'], $this->instance['bundle'], 'full')
+          ->setComponent($this->instance['field_name'], $this->display_options)
+          ->save();
+
+        $this->renderTestEntity($id);
+        switch ($setting) {
+          case 'format_type':
+            // Verify that a date is displayed.
+            $expected = format_date($date->getTimestamp(), $new_value);
+            $this->renderTestEntity($id);
+            $this->assertText($expected, format_string('Formatted date field using %value format displayed as %expected.', array('%value' => $new_value, '%expected' => $expected)));
+            break;
+        }
+      }
+    }
+
+    // Verify that the plain formatter works.
+    $this->display_options['type'] = 'datetime_plain';
+    $display = entity_get_display($this->instance['entity_type'], $this->instance['bundle'], 'full')
+      ->setComponent($this->instance['field_name'], $this->display_options)
+      ->save();
+    $expected = $date->format(DATETIME_DATE_STORAGE_FORMAT);
+    $this->renderTestEntity($id);
+    $this->assertText($expected, format_string('Formatted date field using plain format displayed as %expected.', array('%expected' => $expected)));
+  }
+
+  /**
+   * Tests date and time field.
+   */
+  function testDatetimeField() {
+
+    // Change the field to a datetime field.
+    $this->field['settings']['datetime_type'] = 'datetime';
+    field_update_field($this->field);
+
+    // Display creation form.
+    $this->drupalGet('entity_test/add');
+    $langcode = LANGUAGE_NOT_SPECIFIED;
+    $this->assertFieldByName("{$this->field['field_name']}[$langcode][0][value][date]", '', 'Date element found.');
+    $this->assertFieldByName("{$this->field['field_name']}[$langcode][0][value][time]", '', 'Time element found.');
+
+    // Submit a valid date and ensure it is accepted.
+    $value = '2012-12-31 00:00:00';
+    $date = new DrupalDateTime($value);
+    $format_type = $date->canUseIntl() ? DrupalDateTime::INTL : DrupalDateTime::PHP;
+    $date_format = config('system.date')->get('formats.html_date.pattern.' . $format_type);
+    $time_format = config('system.date')->get('formats.html_time.pattern.' . $format_type);
+
+    $edit = array(
+      'user_id' => 1,
+      'name' => $this->randomName(),
+      "{$this->field['field_name']}[$langcode][0][value][date]" => $date->format($date_format),
+      "{$this->field['field_name']}[$langcode][0][value][time]" => $date->format($time_format),
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+    preg_match('|entity_test/manage/(\d+)/edit|', $this->url, $match);
+    $id = $match[1];
+    $this->assertText(t('entity_test @id has been created.', array('@id' => $id)));
+    $this->assertRaw($date->format($date_format));
+    $this->assertRaw($date->format($time_format));
+
+    // Verify that the date is output according to the formatter settings.
+    $options = array(
+      'format_type' => array('short', 'medium', 'long'),
+    );
+    foreach ($options as $setting => $values) {
+      foreach ($values as $new_value) {
+        // Update the entity display settings.
+        $this->display_options['settings'] = array($setting => $new_value);
+        $display = entity_get_display($this->instance['entity_type'], $this->instance['bundle'], 'full')
+          ->setComponent($this->instance['field_name'], $this->display_options)
+          ->save();
+
+        $this->renderTestEntity($id);
+        switch ($setting) {
+          case 'format_type':
+            // Verify that a date is displayed.
+            $expected = format_date($date->getTimestamp(), $new_value);
+            $this->renderTestEntity($id);
+            $this->assertText($expected, format_string('Formatted date field using %value format displayed as %expected.', array('%value' => $new_value, '%expected' => $expected)));
+            break;
+        }
+      }
+    }
+
+    // Verify that the plain formatter works.
+    $this->display_options['type'] = 'datetime_plain';
+    $display = entity_get_display($this->instance['entity_type'], $this->instance['bundle'], 'full')
+      ->setComponent($this->instance['field_name'], $this->display_options)
+      ->save();
+    $expected = $date->format(DATETIME_DATETIME_STORAGE_FORMAT);
+    $this->renderTestEntity($id);
+    $this->assertText($expected, format_string('Formatted date field using plain format displayed as %expected.', array('%expected' => $expected)));
+  }
+
+  /**
+   * Tests Date List Widget functionality.
+   */
+  function testDatelistWidget() {
+
+    // Change the field to a datetime field.
+    $this->field['settings']['datetime_type'] = 'datetime';
+    field_update_field($this->field);
+
+    // Change the widget to a datelist widget.
+    $increment = 1;
+    $date_order = 'YMD';
+    $time_type = '12';
+
+    $this->instance['widget']['type'] = 'datetime_datelist';
+    $this->instance['widget']['settings'] = array(
+      'increment' => $increment,
+      'date_order' => $date_order,
+      'time_type' => $time_type,
+    );
+    field_update_instance($this->instance);
+    field_cache_clear();
+
+    // Display creation form.
+    $this->drupalGet('entity_test/add');
+    $field_name = $this->field['field_name'];
+    $langcode = LANGUAGE_NOT_SPECIFIED;
+
+    $this->assertFieldByXPath("//*[@id=\"edit-$field_name-$langcode-0-value-year\"]", NULL, 'Year element found.');
+    $this->assertOptionSelected("edit-$field_name-$langcode-0-value-year", '', 'No year selected.');
+    $this->assertFieldByXPath("//*[@id=\"edit-$field_name-$langcode-0-value-month\"]", NULL, 'Month element found.');
+    $this->assertOptionSelected("edit-$field_name-$langcode-0-value-month", '', 'No month selected.');
+    $this->assertFieldByXPath("//*[@id=\"edit-$field_name-$langcode-0-value-day\"]", NULL, 'Day element found.');
+    $this->assertOptionSelected("edit-$field_name-$langcode-0-value-day", '', 'No day selected.');
+    $this->assertFieldByXPath("//*[@id=\"edit-$field_name-$langcode-0-value-hour\"]", NULL, 'Hour element found.');
+    $this->assertOptionSelected("edit-$field_name-$langcode-0-value-hour", '', 'No hour selected.');
+    $this->assertFieldByXPath("//*[@id=\"edit-$field_name-$langcode-0-value-minute\"]", NULL, 'Minute element found.');
+    $this->assertOptionSelected("edit-$field_name-$langcode-0-value-minute", '', 'No minute selected.');
+    $this->assertNoFieldByXPath("//*[@id=\"edit-$field_name-$langcode-0-value-second\"]", NULL, 'Second element not found.');
+    $this->assertFieldByXPath("//*[@id=\"edit-$field_name-$langcode-0-value-ampm\"]", NULL, 'AMPM element found.');
+    $this->assertOptionSelected("edit-$field_name-$langcode-0-value-ampm", '', 'No ampm selected.');
+
+    // Submit a valid date and ensure it is accepted.
+    $date_value = array('year' => 2012, 'month' => 12, 'day' => 31, 'hour' => 5, 'minute' => 15);
+    $date = new DrupalDateTime($date_value);
+
+    $edit = array(
+      'user_id' => 1,
+      'name' => $this->randomName(),
+    );
+    // Add the ampm indicator since we are testing 12 hour time.
+    $date_value['ampm'] = 'am';
+    foreach ($date_value as $part => $value) {
+      $edit["{$this->field['field_name']}[$langcode][0][value][$part]"] = $value;
+    }
+
+    $this->drupalPost(NULL, $edit, t('Save'));
+    preg_match('|entity_test/manage/(\d+)/edit|', $this->url, $match);
+    $id = $match[1];
+    $this->assertText(t('entity_test @id has been created.', array('@id' => $id)));
+
+    $this->assertOptionSelected("edit-$field_name-$langcode-0-value-year", '2012', 'Correct year selected.');
+    $this->assertOptionSelected("edit-$field_name-$langcode-0-value-month", '12', 'Correct month selected.');
+    $this->assertOptionSelected("edit-$field_name-$langcode-0-value-day", '31', 'Correct day selected.');
+    $this->assertOptionSelected("edit-$field_name-$langcode-0-value-hour", '5', 'Correct hour selected.');
+    $this->assertOptionSelected("edit-$field_name-$langcode-0-value-minute", '15', 'Correct minute selected.');
+    $this->assertOptionSelected("edit-$field_name-$langcode-0-value-ampm", 'am', 'Correct ampm selected.');
+  }
+
+  /**
+   * Test default value functionality.
+   */
+  function testDefaultValue() {
+
+    // Change the field to a datetime field.
+    $this->field['settings']['datetime_type'] = 'datetime';
+    field_update_field($this->field);
+
+    // Set the default value to 'now'.
+    $this->instance['settings']['default_value'] = 'now';
+    $this->instance['default_value_function'] = 'datetime_default_value';
+    field_update_instance($this->instance);
+
+    // Display creation form.
+    $date = new DrupalDateTime();
+    $date_format = 'Y-m-d';
+    $this->drupalGet('entity_test/add');
+    $langcode = LANGUAGE_NOT_SPECIFIED;
+
+    // See if current date is set. We cannot test for the precise time because
+    // it may be a few seconds between the time the comparison date is created
+    // and the form date, so we just test the date and that the time is not
+    // empty.
+    $this->assertFieldByName("{$this->field['field_name']}[$langcode][0][value][date]", $date->format($date_format), 'Date element found.');
+    $this->assertNoFieldByName("{$this->field['field_name']}[$langcode][0][value][time]", '', 'Time element found.');
+
+    // Set the default value to 'blank'.
+    $this->instance['settings']['default_value'] = 'blank';
+    field_update_instance($this->instance);
+
+    // Display creation form.
+    $date = new DrupalDateTime();
+    $this->drupalGet('entity_test/add');
+
+    // See that no date is set.
+    $this->assertFieldByName("{$this->field['field_name']}[$langcode][0][value][date]", '', 'Date element found.');
+    $this->assertFieldByName("{$this->field['field_name']}[$langcode][0][value][time]", '', 'Time element found.');
+  }
+
+  /**
+   * Test that invalid values are caught and marked as invalid.
+   */
+  function testInvalidField() {
+
+    // Change the field to a datetime field.
+    $this->field['settings']['datetime_type'] = 'datetime';
+    field_update_field($this->field);
+
+    // Display creation form.
+    $this->drupalGet('entity_test/add');
+    $langcode = LANGUAGE_NOT_SPECIFIED;
+    $this->assertFieldByName("{$this->field['field_name']}[$langcode][0][value][date]", '', 'Date element found.');
+    $this->assertFieldByName("{$this->field['field_name']}[$langcode][0][value][time]", '', 'Time element found.');
+
+    // Submit invalid dates and ensure they is not accepted.
+    $date_value = '';
+    $edit = array(
+      "{$this->field['field_name']}[$langcode][0][value][date]" => $date_value,
+      "{$this->field['field_name']}[$langcode][0][value][time]" => '12:00:00',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->assertText('date is invalid', 'Empty date value has been caught.');
+
+    $date_value = 'aaaa-12-01';
+    $edit = array(
+      "{$this->field['field_name']}[$langcode][0][value][date]" => $date_value,
+      "{$this->field['field_name']}[$langcode][0][value][time]" => '00:00:00',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->assertText('date is invalid', format_string('Invalid year value %date has been caught.', array('%date' => $date_value)));
+
+    $date_value = '2012-75-01';
+    $edit = array(
+      "{$this->field['field_name']}[$langcode][0][value][date]" => $date_value,
+      "{$this->field['field_name']}[$langcode][0][value][time]" => '00:00:00',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->assertText('date is invalid', format_string('Invalid month value %date has been caught.', array('%date' => $date_value)));
+
+    $date_value = '2012-12-99';
+    $edit = array(
+      "{$this->field['field_name']}[$langcode][0][value][date]" => $date_value,
+      "{$this->field['field_name']}[$langcode][0][value][time]" => '00:00:00',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->assertText('date is invalid', format_string('Invalid day value %date has been caught.', array('%date' => $date_value)));
+
+    $date_value = '2012-12-01';
+    $time_value = '';
+    $edit = array(
+      "{$this->field['field_name']}[$langcode][0][value][date]" => $date_value,
+      "{$this->field['field_name']}[$langcode][0][value][time]" => $time_value,
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->assertText('date is invalid', 'Empty time value has been caught.');
+
+    $date_value = '2012-12-01';
+    $time_value = '49:00:00';
+    $edit = array(
+      "{$this->field['field_name']}[$langcode][0][value][date]" => $date_value,
+      "{$this->field['field_name']}[$langcode][0][value][time]" => $time_value,
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->assertText('date is invalid', format_string('Invalid hour value %time has been caught.', array('%time' => $time_value)));
+
+    $date_value = '2012-12-01';
+    $time_value = '12:99:00';
+    $edit = array(
+      "{$this->field['field_name']}[$langcode][0][value][date]" => $date_value,
+      "{$this->field['field_name']}[$langcode][0][value][time]" => $time_value,
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->assertText('date is invalid', format_string('Invalid minute value %time has been caught.', array('%time' => $time_value)));
+
+    $date_value = '2012-12-01';
+    $time_value = '12:15:99';
+    $edit = array(
+      "{$this->field['field_name']}[$langcode][0][value][date]" => $date_value,
+      "{$this->field['field_name']}[$langcode][0][value][time]" => $time_value,
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->assertText('date is invalid', format_string('Invalid second value %time has been caught.', array('%time' => $time_value)));
+  }
+
+  /**
+   * Renders a entity_test and sets the output in the internal browser.
+   *
+   * @param int $id
+   *   The entity_test ID to render.
+   * @param string $view_mode
+   *   (optional) The view mode to use for rendering. Defaults to 'full'.
+   * @param bool $reset
+   *   (optional) Whether to reset the entity_test controller cache. Defaults to
+   *   TRUE to simplify testing.
+   */
+  protected function renderTestEntity($id, $view_mode = 'full', $reset = TRUE) {
+    if ($reset) {
+      entity_get_controller('entity_test')->resetCache(array($id));
+    }
+    $entity = entity_load('entity_test', $id);
+    $display = entity_get_display('entity_test', $entity->bundle(), 'full');
+    field_attach_prepare_view('entity_test', array($entity->id() => $entity), array($entity->bundle() => $display), $view_mode);
+    $entity->content = field_attach_view($entity, $display, $view_mode);
+
+    $output = drupal_render($entity->content);
+    $this->drupalSetContent($output);
+    $this->verbose($output);
+  }
+
+}
diff --git a/core/modules/edit/lib/Drupal/edit/MetadataGenerator.php b/core/modules/edit/lib/Drupal/edit/MetadataGenerator.php
index 3ec8ce2..df0217a 100644
--- a/core/modules/edit/lib/Drupal/edit/MetadataGenerator.php
+++ b/core/modules/edit/lib/Drupal/edit/MetadataGenerator.php
@@ -69,8 +69,7 @@ public function generate(EntityInterface $entity, FieldInstance $instance, $lang
 
     // Early-return if no editor is available.
     $formatter_id = entity_get_render_display($entity, $view_mode)->getFormatter($instance['field_name'])->getPluginId();
-    $items = $entity->get($field_name);
-    $items = $items[$langcode];
+    $items = $entity->get($field_name)->getValue();
     $editor_id = $this->editorSelector->getEditor($formatter_id, $instance, $items);
     if (!isset($editor_id)) {
       return array('access' => FALSE);
diff --git a/core/modules/edit/lib/Drupal/edit/Tests/EditTestBase.php b/core/modules/edit/lib/Drupal/edit/Tests/EditTestBase.php
index c3a91fb..d614829 100644
--- a/core/modules/edit/lib/Drupal/edit/Tests/EditTestBase.php
+++ b/core/modules/edit/lib/Drupal/edit/Tests/EditTestBase.php
@@ -20,8 +20,7 @@ class EditTestBase extends DrupalUnitTestBase {
    *
    * @var array
    */
-  public static $modules = array('system', 'entity', 'field', 'field_sql_storage', 'field_test', 'number', 'text', 'edit');
-
+  public static $modules = array('system', 'entity', 'entity_test', 'field', 'field_sql_storage', 'field_test', 'number', 'text', 'edit');
   /**
    * Sets the default field storage backend for fields created during tests.
    */
@@ -30,7 +29,7 @@ function setUp() {
 
     $this->installSchema('system', 'variable');
     $this->installSchema('field', array('field_config', 'field_config_instance'));
-    $this->installSchema('field_test', 'test_entity');
+    $this->installSchema('entity_test', 'entity_test');
 
     // Set default storage backend.
     variable_set('field_storage_default', $this->default_storage);
@@ -69,8 +68,8 @@ function createFieldWithInstance($field_name, $type, $cardinality, $label, $inst
     $instance = $field_name . '_instance';
     $this->$instance = array(
       'field_name' => $field_name,
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle',
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
       'label' => $label,
       'description' => $label,
       'weight' => mt_rand(0, 127),
@@ -83,7 +82,7 @@ function createFieldWithInstance($field_name, $type, $cardinality, $label, $inst
     );
     field_create_instance($this->$instance);
 
-    entity_get_display('test_entity', 'test_bundle', 'default')
+    entity_get_display('entity_test', 'entity_test', 'default')
       ->setComponent($field_name, array(
         'label' => 'above',
         'type' => $formatter_type,
diff --git a/core/modules/edit/lib/Drupal/edit/Tests/EditorSelectionTest.php b/core/modules/edit/lib/Drupal/edit/Tests/EditorSelectionTest.php
index fdddec0..e7a6db1 100644
--- a/core/modules/edit/lib/Drupal/edit/Tests/EditorSelectionTest.php
+++ b/core/modules/edit/lib/Drupal/edit/Tests/EditorSelectionTest.php
@@ -49,8 +49,8 @@ function setUp() {
    * editor that Edit selects.
    */
   protected function getSelectedEditor($items, $field_name, $view_mode = 'default') {
-    $options = entity_get_display('test_entity', 'test_bundle', $view_mode)->getComponent($field_name);
-    $field_instance = field_info_instance('test_entity', $field_name, 'test_bundle');
+    $options = entity_get_display('entity_test', 'entity_test', $view_mode)->getComponent($field_name);
+    $field_instance = field_info_instance('entity_test', $field_name, 'entity_test');
     return $this->editorSelector->getEditor($options['type'], $field_instance, $items);
   }
 
diff --git a/core/modules/edit/lib/Drupal/edit/Tests/MetadataGeneratorTest.php b/core/modules/edit/lib/Drupal/edit/Tests/MetadataGeneratorTest.php
index 529d535..e41e6ed 100644
--- a/core/modules/edit/lib/Drupal/edit/Tests/MetadataGeneratorTest.php
+++ b/core/modules/edit/lib/Drupal/edit/Tests/MetadataGeneratorTest.php
@@ -96,12 +96,12 @@ function testSimpleEntityType() {
     );
 
     // Create an entity with values for this text field.
-    $this->entity = field_test_create_entity();
+    $this->entity = entity_create('entity_test', array());
     $this->is_new = TRUE;
-    $this->entity->{$field_1_name}[LANGUAGE_NOT_SPECIFIED] = array(array('value' => 'Test'));
-    $this->entity->{$field_2_name}[LANGUAGE_NOT_SPECIFIED] = array(array('value' => 42));
-    field_test_entity_save($this->entity);
-    $entity = entity_load('test_entity', $this->entity->ftid);
+    $this->entity->{$field_1_name}->value = 'Test';
+    $this->entity->{$field_2_name}->value = 42;
+    $this->entity->save();
+    $entity = entity_load('entity_test', $this->entity->id());
 
     // Verify metadata for field 1.
     $instance_1 = field_info_instance($entity->entityType(), $field_1_name, $entity->bundle());
@@ -110,7 +110,7 @@ function testSimpleEntityType() {
       'access' => TRUE,
       'label' => 'Simple text field',
       'editor' => 'direct',
-      'aria' => 'Entity test_entity 1, field Simple text field',
+      'aria' => 'Entity entity_test 1, field Simple text field',
     );
     $this->assertEqual($expected_1, $metadata_1, 'The correct metadata is generated for the first field.');
 
@@ -121,7 +121,7 @@ function testSimpleEntityType() {
       'access' => TRUE,
       'label' => 'Simple number field',
       'editor' => 'form',
-      'aria' => 'Entity test_entity 1, field Simple number field',
+      'aria' => 'Entity entity_test 1, field Simple number field',
     );
     $this->assertEqual($expected_2, $metadata_2, 'The correct metadata is generated for the second field.');
   }
@@ -164,11 +164,11 @@ function testEditorWithCustomMetadata() {
     $full_html_format->save();
 
     // Create an entity with values for this rich text field.
-    $this->entity = field_test_create_entity();
-    $this->is_new = TRUE;
-    $this->entity->{$field_name}[LANGUAGE_NOT_SPECIFIED] = array(array('value' => 'Test', 'format' => 'full_html'));
-    field_test_entity_save($this->entity);
-    $entity = entity_load('test_entity', $this->entity->ftid);
+    $this->entity = entity_create('entity_test', array());
+    $this->entity->{$field_name}->value = 'Test';
+    $this->entity->{$field_name}->format = 'full_html';
+    $this->entity->save();
+    $entity = entity_load('entity_test', $this->entity->id());
 
     // Verify metadata.
     $instance = field_info_instance($entity->entityType(), $field_name, $entity->bundle());
@@ -177,7 +177,7 @@ function testEditorWithCustomMetadata() {
       'access' => TRUE,
       'label' => 'Rich text field',
       'editor' => 'wysiwyg',
-      'aria' => 'Entity test_entity 1, field Rich text field',
+      'aria' => 'Entity entity_test 1, field Rich text field',
       'custom' => array(
         'format' => 'full_html'
       ),
diff --git a/core/modules/editor/lib/Drupal/editor/Tests/EditorLoadingTest.php b/core/modules/editor/lib/Drupal/editor/Tests/EditorLoadingTest.php
index 755c2c0..e885ac4 100644
--- a/core/modules/editor/lib/Drupal/editor/Tests/EditorLoadingTest.php
+++ b/core/modules/editor/lib/Drupal/editor/Tests/EditorLoadingTest.php
@@ -137,9 +137,9 @@ function testLoading() {
     // to let the untrusted user edit it.
     $this->drupalCreateNode(array(
       'type' => 'article',
-      'body' => array(LANGUAGE_NOT_SPECIFIED => array(
-        0 => array('value' => $this->randomName(32), 'format' => 'full_html')
-      )),
+      'body' => array(
+        array('value' => $this->randomName(32), 'format' => 'full_html')
+      ),
     ));
 
     // The untrusted user tries to edit content that is written in a text format
diff --git a/core/modules/email/lib/Drupal/email/Tests/EmailFieldTest.php b/core/modules/email/lib/Drupal/email/Tests/EmailFieldTest.php
index c719c97..8548c2a 100644
--- a/core/modules/email/lib/Drupal/email/Tests/EmailFieldTest.php
+++ b/core/modules/email/lib/Drupal/email/Tests/EmailFieldTest.php
@@ -19,7 +19,7 @@ class EmailFieldTest extends WebTestBase {
    *
    * @var array
    */
-  public static $modules = array('node', 'field_test', 'email', 'field_ui');
+  public static $modules = array('node', 'entity_test', 'email', 'field_ui');
 
   public static function getInfo() {
     return array(
@@ -33,8 +33,8 @@ function setUp() {
     parent::setUp();
 
     $this->web_user = $this->drupalCreateUser(array(
-      'access field_test content',
-      'administer field_test content',
+      'view test entity',
+      'administer entity_test content',
       'administer content types',
     ));
     $this->drupalLogin($this->web_user);
@@ -52,8 +52,8 @@ function testEmailField() {
     field_create_field($this->field);
     $this->instance = array(
       'field_name' => $this->field['field_name'],
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle',
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
       'widget' => array(
         'type' => 'email_default',
         'settings' => array(
@@ -63,14 +63,14 @@ function testEmailField() {
     );
     field_create_instance($this->instance);
     // Create a display for the full view mode.
-    entity_get_display('test_entity', 'test_bundle', 'full')
+    entity_get_display('entity_test', 'entity_test', 'full')
       ->setComponent($this->field['field_name'], array(
         'type' => 'email_mailto',
       ))
       ->save();
 
     // Display creation form.
-    $this->drupalGet('test-entity/add/test_bundle');
+    $this->drupalGet('entity_test/add');
     $langcode = LANGUAGE_NOT_SPECIFIED;
     $this->assertFieldByName("{$this->field['field_name']}[$langcode][0][value]", '', 'Widget found.');
     $this->assertRaw('placeholder="example@example.com"');
@@ -78,16 +78,18 @@ function testEmailField() {
     // Submit a valid e-mail address and ensure it is accepted.
     $value = 'test@example.com';
     $edit = array(
+      'user_id' => 1,
+      'name' => $this->randomName(),
       "{$this->field['field_name']}[$langcode][0][value]" => $value,
     );
     $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
+    preg_match('|entity_test/manage/(\d+)/edit|', $this->url, $match);
     $id = $match[1];
-    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)));
+    $this->assertText(t('entity_test @id has been created.', array('@id' => $id)));
     $this->assertRaw($value);
 
     // Verify that a mailto link is displayed.
-    $entity = field_test_entity_test_load($id);
+    $entity = entity_load('entity_test', $id);
     $display = entity_get_display($entity->entityType(), $entity->bundle(), 'full');
     $entity->content = field_attach_view($entity, $display);
     $this->drupalSetContent(drupal_render($entity->content));
diff --git a/core/modules/entity_reference/entity_reference.module b/core/modules/entity_reference/entity_reference.module
index f5e968c..3566121 100644
--- a/core/modules/entity_reference/entity_reference.module
+++ b/core/modules/entity_reference/entity_reference.module
@@ -35,24 +35,32 @@ function entity_reference_field_info() {
 }
 
 /**
- * Implements hook_entity_field_info().
+ * Implements hook_entity_field_info_alter().
  *
  * Set the "target_type" property definition for entity reference fields.
  *
  * @see \Drupal\Core\Entity\Field\Type\EntityReferenceItem::getPropertyDefinitions()
+ *
+ * @param array $info
+ *   The property info array as returned by hook_entity_field_info().
+ * @param string $entity_type
+ *   The entity type for which entity properties are defined.
  */
-function entity_reference_entity_field_info($entity_type) {
-  $property_info = array();
+function entity_reference_entity_field_info_alter(&$info, $entity_type) {
   foreach (field_info_instances($entity_type) as $bundle_name => $instances) {
     foreach ($instances as $field_name => $instance) {
       $field = field_info_field($field_name);
       if ($field['type'] != 'entity_reference') {
         continue;
       }
-      $property_info['definitions'][$field_name]['settings']['target_type'] = $field['settings']['target_type'];
+      if (isset($info['definitions'][$field_name])) {
+        $info['definitions'][$field_name]['settings']['target_type'] = $field['settings']['target_type'];
+      }
+      elseif (isset($info['optional'][$field_name])) {
+        $info['optional'][$field_name]['settings']['target_type'] = $field['settings']['target_type'];
+      }
     }
   }
-  return $property_info;
 }
 
 /**
diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceSelectionSortTest.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceSelectionSortTest.php
index cc768e2..d3245e0 100644
--- a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceSelectionSortTest.php
+++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceSelectionSortTest.php
@@ -88,10 +88,8 @@ public function testSort() {
         'title' => 'Node published1 (<&>)',
         'uid' => 1,
         'field_text' => array(
-          LANGUAGE_NOT_SPECIFIED => array(
-            array(
-              'value' => 1,
-            ),
+          array(
+            'value' => 1,
           ),
         ),
       ),
@@ -101,10 +99,8 @@ public function testSort() {
         'title' => 'Node published2 (<&>)',
         'uid' => 1,
         'field_text' => array(
-          LANGUAGE_NOT_SPECIFIED => array(
-            array(
-              'value' => 2,
-            ),
+          array(
+            'value' => 2,
           ),
         ),
       ),
diff --git a/core/modules/field/field.api.php b/core/modules/field/field.api.php
index 16b0143..1cf252d 100644
--- a/core/modules/field/field.api.php
+++ b/core/modules/field/field.api.php
@@ -1086,7 +1086,7 @@ function hook_field_attach_view_alter(&$output, $context) {
     $element = &$output[$field_name];
     if ($element['#field_type'] == 'entity_reference' && $element['#formatter'] == 'entity_reference_label') {
       foreach ($element['#items'] as $delta => $item) {
-        $term = $item['taxonomy_term'];
+        $term = $item['entity'];
         if (!empty($term->rdf_mapping['rdftype'])) {
           $element[$delta]['#options']['attributes']['typeof'] = $term->rdf_mapping['rdftype'];
         }
diff --git a/core/modules/field/field.module b/core/modules/field/field.module
index a52d917..9fb597b 100644
--- a/core/modules/field/field.module
+++ b/core/modules/field/field.module
@@ -393,7 +393,7 @@ function field_entity_create(EntityInterface $entity) {
   $info = $entity->entityInfo();
   if (!empty($info['fieldable'])) {
     foreach ($entity->getTranslationLanguages() as $langcode => $language) {
-      field_populate_default_values($entity, $langcode);
+      field_populate_default_values($entity->getBCEntity(), $langcode);
     }
   }
 }
@@ -944,7 +944,10 @@ function field_view_field(EntityInterface $entity, $field_name, $display_options
 
   if ($formatter) {
     $display_langcode = field_language($entity, $field_name, $langcode);
-    $items = $entity->{$field_name}[$display_langcode];
+    $items = array();
+    if (isset($entity->{$field_name}[$display_langcode])) {
+      $items = $entity->{$field_name}[$display_langcode];
+    }
 
     // Invoke prepare_view steps if needed.
     if (empty($entity->_field_view_prepared)) {
@@ -956,7 +959,10 @@ function field_view_field(EntityInterface $entity, $field_name, $display_options
       _field_invoke_multiple('prepare_view', $entity->entityType(), array($id => $entity), $null, $null, $options);
 
       // Then let the formatter do its own specific massaging.
-      $items_multi = array($id => $entity->{$field_name}[$display_langcode]);
+      $items_multi = array($id => array());
+      if (isset($entity->{$field_name}[$display_langcode])) {
+        $items_multi[$id] = $entity->{$field_name}[$display_langcode];
+      }
       $formatter->prepareView(array($id => $entity), $display_langcode, $items_multi);
       $items = $items_multi[$id];
     }
diff --git a/core/modules/field/lib/Drupal/field/Tests/BulkDeleteTest.php b/core/modules/field/lib/Drupal/field/Tests/BulkDeleteTest.php
index c365961..b3be69a 100644
--- a/core/modules/field/lib/Drupal/field/Tests/BulkDeleteTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/BulkDeleteTest.php
@@ -17,7 +17,7 @@ class BulkDeleteTest extends FieldTestBase {
    *
    * @var array
    */
-  public static $modules = array('field_test');
+  public static $modules = array('field_test', 'entity_test');
 
   protected $field;
 
@@ -49,10 +49,10 @@ protected function convertToPartialEntities($entities, $field_name) {
       // Re-create the entity to match what is expected
       // _field_create_entity_from_ids().
       $ids = (object) array(
-        'entity_id' => $entity->ftid,
-        'revision_id' => $entity->ftvid,
-        'bundle' => $entity->fttype,
-        'entity_type' => 'test_entity',
+        'entity_id' => $entity->id(),
+        'revision_id' => $entity->getRevisionId(),
+        'bundle' => 'entity_test',
+        'entity_type' => 'entity_test',
       );
       $partial_entities[$id] = _field_create_entity_from_ids($ids);
       $partial_entities[$id]->$field_name = $entity->$field_name;
@@ -103,7 +103,7 @@ function setUp() {
     // Create two bundles.
     $this->bundles = array('bb_1' => 'bb_1', 'bb_2' => 'bb_2');
     foreach ($this->bundles as $name => $desc) {
-      field_test_create_bundle($name, $desc);
+      entity_test_create_bundle($name, $desc);
     }
 
     // Create two fields.
@@ -114,8 +114,7 @@ function setUp() {
 
     // For each bundle, create an instance of each field, and 10
     // entities with values for each field.
-    $id = 1;
-    $this->entity_type = 'test_entity';
+    $this->entity_type = 'entity_test';
     foreach ($this->bundles as $bundle) {
       foreach ($this->fields as $field) {
         $instance = array(
@@ -128,20 +127,18 @@ function setUp() {
         );
         $this->instances[] = field_create_instance($instance);
       }
-
       for ($i = 0; $i < 10; $i++) {
-        $entity = field_test_create_entity($id, $id, $bundle);
+        $entity = entity_create($this->entity_type, array('type' => $bundle));
         foreach ($this->fields as $field) {
-          $entity->{$field['field_name']}[LANGUAGE_NOT_SPECIFIED] = $this->_generateTestFieldValues($field['cardinality']);
+        $entity->{$field['field_name']}->setValue($this->_generateTestFieldValues($field['cardinality']));
         }
         $entity->save();
-        $id++;
       }
     }
-    $this->entities = entity_load_multiple($this->entity_type, range(1, $id));
+    $this->entities = entity_load_multiple($this->entity_type);
     foreach ($this->entities as $entity) {
       // Also keep track of the entities per bundle.
-      $this->entities_by_bundles[$entity->fttype][$entity->ftid] = $entity;
+      $this->entities_by_bundles[$entity->bundle()][$entity->id()] = $entity;
     }
   }
 
@@ -161,8 +158,8 @@ function testDeleteFieldInstance() {
     $factory = drupal_container()->get('entity.query');
 
     // There are 10 entities of this bundle.
-    $found = $factory->get('test_entity')
-      ->condition('fttype', $bundle)
+    $found = $factory->get('entity_test')
+      ->condition('type', $bundle)
       ->execute();
     $this->assertEqual(count($found), 10, 'Correct number of entities found before deleting');
 
@@ -176,21 +173,21 @@ function testDeleteFieldInstance() {
     $this->assertEqual($instances[0]['bundle'], $bundle, 'The deleted instance is for the correct bundle');
 
     // There are 0 entities of this bundle with non-deleted data.
-    $found = $factory->get('test_entity')
-      ->condition('fttype', $bundle)
+    $found = $factory->get('entity_test')
+      ->condition('type', $bundle)
       ->condition("$field_name.deleted", 0)
       ->execute();
     $this->assertFalse($found, 'No entities found after deleting');
 
     // There are 10 entities of this bundle when deleted fields are allowed, and
     // their values are correct.
-    $found = $factory->get('test_entity')
-      ->condition('fttype', $bundle)
+    $found = $factory->get('entity_test')
+      ->condition('type', $bundle)
       ->condition("$field_name.deleted", 1)
-      ->sort('ftid')
+      ->sort('id')
       ->execute();
     $ids = (object) array(
-      'entity_type' => 'test_entity',
+      'entity_type' => 'entity_test',
       'bundle' => $bundle,
     );
     $entities = array();
@@ -201,7 +198,7 @@ function testDeleteFieldInstance() {
     field_attach_load($this->entity_type, $entities, FIELD_LOAD_CURRENT, array('field_id' => $field['id'], 'deleted' => 1));
     $this->assertEqual(count($found), 10, 'Correct number of entities found after deleting');
     foreach ($entities as $id => $entity) {
-      $this->assertEqual($this->entities[$id]->{$field['field_name']}, $entity->{$field['field_name']}, "Entity $id with deleted data loaded correctly");
+      $this->assertEqual($this->entities[$id]->{$field['field_name']}->value, $entity->{$field['field_name']}[LANGUAGE_NOT_SPECIFIED][0]['value'], "Entity $id with deleted data loaded correctly");
     }
   }
 
@@ -230,8 +227,8 @@ function testPurgeInstance() {
       field_purge_batch($batch_size);
 
       // There are $count deleted entities left.
-      $found = entity_query('test_entity')
-        ->condition('fttype', $bundle)
+      $found = entity_query('entity_test')
+        ->condition('type', $bundle)
         ->condition($field['field_name'] . '.deleted', 1)
         ->execute();
       $this->assertEqual(count($found), $count, 'Correct number of entities found after purging 2');
diff --git a/core/modules/field/lib/Drupal/field/Tests/CrudTest.php b/core/modules/field/lib/Drupal/field/Tests/CrudTest.php
index 1c539da..161e376 100644
--- a/core/modules/field/lib/Drupal/field/Tests/CrudTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/CrudTest.php
@@ -17,7 +17,7 @@ class CrudTest extends FieldTestBase {
    *
    * @var array
    */
-  public static $modules = array('field_test', 'number');
+  public static $modules = array('field_test', 'number', 'entity_test');
 
   public static function getInfo() {
     return array(
@@ -215,14 +215,14 @@ function testReadFields() {
     // Create an instance of the field.
     $instance_definition = array(
       'field_name' => $field_definition['field_name'],
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle',
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
     );
     field_create_instance($instance_definition);
 
     // Check that criteria spanning over the field_config_instance table work.
     $fields = field_read_fields(array('entity_type' => $instance_definition['entity_type'], 'bundle' => $instance_definition['bundle']));
-    $this->assertTrue(count($fields) == 1 && isset($fields[$field_definition['field_name']]), 'The field was properly read.');
+    $this->assertTrue(count($fields) == 2 && isset($fields[$field_definition['field_name']]), 'The field was properly read.');
     $fields = field_read_fields(array('entity_type' => $instance_definition['entity_type'], 'field_name' => $instance_definition['field_name']));
     $this->assertTrue(count($fields) == 1 && isset($fields[$field_definition['field_name']]), 'The field was properly read.');
   }
@@ -285,8 +285,8 @@ function testDeleteField() {
     // Create instances for each.
     $this->instance_definition = array(
       'field_name' => $this->field['field_name'],
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle',
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
       'widget' => array(
         'type' => 'test_field_widget',
       ),
@@ -308,7 +308,7 @@ function testDeleteField() {
 
     // Make sure that this field's instance is marked as deleted when it is
     // specifically loaded.
-    $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle'], array('include_deleted' => TRUE));
+    $instance = field_read_instance('entity_test', $this->instance_definition['field_name'], $this->instance_definition['bundle'], array('include_deleted' => TRUE));
     $this->assertTrue(!empty($instance['deleted']), 'An instance for a deleted field is marked for deletion.');
 
     // Try to load the field normally and make sure it does not show up.
@@ -316,13 +316,13 @@ function testDeleteField() {
     $this->assertTrue(empty($field), 'A deleted field is not loaded by default.');
 
     // Try to load the instance normally and make sure it does not show up.
-    $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
+    $instance = field_read_instance('entity_test', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
     $this->assertTrue(empty($instance), 'An instance for a deleted field is not loaded by default.');
 
     // Make sure the other field (and its field instance) are not deleted.
     $another_field = field_read_field($this->another_field['field_name']);
     $this->assertTrue(!empty($another_field) && empty($another_field['deleted']), 'A non-deleted field is not marked for deletion.');
-    $another_instance = field_read_instance('test_entity', $this->another_instance_definition['field_name'], $this->another_instance_definition['bundle']);
+    $another_instance = field_read_instance('entity_test', $this->another_instance_definition['field_name'], $this->another_instance_definition['bundle']);
     $this->assertTrue(!empty($another_instance) && empty($another_instance['deleted']), 'An instance of a non-deleted field is not marked for deletion.');
 
     // Try to create a new field the same name as a deleted field and
@@ -331,23 +331,22 @@ function testDeleteField() {
     field_create_instance($this->instance_definition);
     $field = field_read_field($this->field['field_name']);
     $this->assertTrue(!empty($field) && empty($field['deleted']), 'A new field with a previously used name is created.');
-    $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
+    $instance = field_read_instance('entity_test', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
     $this->assertTrue(!empty($instance) && empty($instance['deleted']), 'A new instance for a previously used field name is created.');
 
     // Save an entity with data for the field
-    $entity = field_test_create_entity(0, 0, $instance['bundle']);
+    $entity = entity_create('entity_test', array('id' => 0, 'revision_id' => 0));
     $langcode = LANGUAGE_NOT_SPECIFIED;
     $values[0]['value'] = mt_rand(1, 127);
-    $entity->{$field['field_name']}[$langcode] = $values;
-    $entity_type = 'test_entity';
-    field_attach_insert($entity);
+    $entity->{$field['field_name']}->value = $values[0]['value'];
+    field_attach_insert($entity->getBCEntity());
 
     // Verify the field is present on load
-    $entity = field_test_create_entity(0, 0, $this->instance_definition['bundle']);
-    field_attach_load($entity_type, array(0 => $entity));
-    $this->assertIdentical(count($entity->{$field['field_name']}[$langcode]), count($values), "Data in previously deleted field saves and loads correctly");
+    $entity = entity_create('entity_test', array('id' => 0, 'revision_id' => 0));
+    field_attach_load('entity_test', array(0 => $entity->getBCEntity()));
+    $this->assertIdentical(count($entity->{$field['field_name']}), count($values), "Data in previously deleted field saves and loads correctly");
     foreach ($values as $delta => $value) {
-      $this->assertEqual($entity->{$field['field_name']}[$langcode][$delta]['value'], $values[$delta]['value'], "Data in previously deleted field saves and loads correctly");
+      $this->assertEqual($entity->{$field['field_name']}[$delta]->value, $values[$delta]['value'], "Data in previously deleted field saves and loads correctly");
     }
   }
 
@@ -392,28 +391,28 @@ function testUpdateField() {
     $field_definition = field_create_field($field_definition);
     $instance = array(
       'field_name' => 'field_update',
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle',
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
     );
     $instance = field_create_instance($instance);
 
     do {
       // We need a unique ID for our entity. $cardinality will do.
       $id = $cardinality;
-      $entity = field_test_create_entity($id, $id, $instance['bundle']);
+      $entity = entity_create('entity_test', array('id' => $id, 'revision_id' => $id));
       // Fill in the entity with more values than $cardinality.
       for ($i = 0; $i < 20; $i++) {
-        $entity->field_update[LANGUAGE_NOT_SPECIFIED][$i]['value'] = $i;
+        $entity->field_update[$i]->value = $i;
       }
       // Save the entity.
-      field_attach_insert($entity);
+      field_attach_insert($entity->getBCEntity());
       // Load back and assert there are $cardinality number of values.
-      $entity = field_test_create_entity($id, $id, $instance['bundle']);
-      field_attach_load('test_entity', array($id => $entity));
-      $this->assertEqual(count($entity->field_update[LANGUAGE_NOT_SPECIFIED]), $field_definition['cardinality'], 'Cardinality is kept');
+      $entity = entity_create('entity_test', array('id' => $id, 'revision_id' => $id));
+      field_attach_load('entity_test', array($id => $entity->getBCEntity()));
+      $this->assertEqual(count($entity->field_update), $field_definition['cardinality'], 'Cardinality is kept');
       // Now check the values themselves.
       for ($delta = 0; $delta < $cardinality; $delta++) {
-        $this->assertEqual($entity->field_update[LANGUAGE_NOT_SPECIFIED][$delta]['value'], $delta, 'Value is kept');
+        $this->assertEqual($entity->field_update[$delta]->value, $delta, 'Value is kept');
       }
       // Increase $cardinality and set the field cardinality to the new value.
       $field_definition['cardinality'] = ++$cardinality;
diff --git a/core/modules/field/lib/Drupal/field/Tests/DisplayApiTest.php b/core/modules/field/lib/Drupal/field/Tests/DisplayApiTest.php
index 8c28727..b4ffe84 100644
--- a/core/modules/field/lib/Drupal/field/Tests/DisplayApiTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/DisplayApiTest.php
@@ -14,7 +14,14 @@ class DisplayApiTest extends FieldTestBase {
    *
    * @var array
    */
-  public static $modules = array('field_test');
+  public static $modules = array('field_test', 'entity_test');
+
+  /**
+   * The test entity.
+   *
+   * @var \Drupal\Core\Entity\EntityInterface
+   */
+  protected $entity;
 
   public static function getInfo() {
     return array(
@@ -39,8 +46,8 @@ function setUp() {
     );
     $this->instance = array(
       'field_name' => $this->field_name,
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle',
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
       'label' => $this->label,
     );
 
@@ -72,10 +79,9 @@ function setUp() {
 
     // Create an entity with values.
     $this->values = $this->_generateTestFieldValues($this->cardinality);
-    $this->entity = field_test_create_entity();
-    $this->is_new = TRUE;
-    $this->entity->{$this->field_name}[LANGUAGE_NOT_SPECIFIED] = $this->values;
-    field_test_entity_save($this->entity);
+    $this->entity = entity_create('entity_test', array());
+    $this->entity->{$this->field_name}->setValue($this->values);
+    $this->entity->save();
   }
 
   /**
@@ -83,7 +89,7 @@ function setUp() {
    */
   function testFieldViewField() {
     // No display settings: check that default display settings are used.
-    $output = field_view_field($this->entity, $this->field_name);
+    $output = field_view_field($this->entity->getBCEntity(), $this->field_name);
     $this->drupalSetContent(drupal_render($output));
     $settings = field_info_formatter_settings('field_test_default');
     $setting = $settings['test_formatter_setting'];
@@ -101,7 +107,7 @@ function testFieldViewField() {
         'alter' => TRUE,
       ),
     );
-    $output = field_view_field($this->entity, $this->field_name, $display);
+    $output = field_view_field($this->entity->getBCEntity(), $this->field_name, $display);
     $this->drupalSetContent(drupal_render($output));
     $setting = $display['settings']['test_formatter_setting_multiple'];
     $this->assertNoText($this->label, 'Label was not displayed.');
@@ -120,7 +126,7 @@ function testFieldViewField() {
         'test_formatter_setting_additional' => $this->randomName(),
       ),
     );
-    $output = field_view_field($this->entity, $this->field_name, $display);
+    $output = field_view_field($this->entity->getBCEntity(), $this->field_name, $display);
     $view = drupal_render($output);
     $this->drupalSetContent($view);
     $setting = $display['settings']['test_formatter_setting_additional'];
@@ -132,7 +138,7 @@ function testFieldViewField() {
 
     // View mode: check that display settings specified in the display object
     // are used.
-    $output = field_view_field($this->entity, $this->field_name, 'teaser');
+    $output = field_view_field($this->entity->getBCEntity(), $this->field_name, 'teaser');
     $this->drupalSetContent(drupal_render($output));
     $setting = $this->display_options['teaser']['settings']['test_formatter_setting'];
     $this->assertText($this->label, 'Label was displayed.');
@@ -142,7 +148,7 @@ function testFieldViewField() {
 
     // Unknown view mode: check that display settings for 'default' view mode
     // are used.
-    $output = field_view_field($this->entity, $this->field_name, 'unknown_view_mode');
+    $output = field_view_field($this->entity->getBCEntity(), $this->field_name, 'unknown_view_mode');
     $this->drupalSetContent(drupal_render($output));
     $setting = $this->display_options['default']['settings']['test_formatter_setting'];
     $this->assertText($this->label, 'Label was displayed.');
@@ -159,8 +165,8 @@ function testFieldViewValue() {
     $settings = field_info_formatter_settings('field_test_default');
     $setting = $settings['test_formatter_setting'];
     foreach ($this->values as $delta => $value) {
-      $item = $this->entity->{$this->field_name}[LANGUAGE_NOT_SPECIFIED][$delta];
-      $output = field_view_value($this->entity, $this->field_name, $item);
+      $item = $this->entity->{$this->field_name}[$delta]->getValue();
+      $output = field_view_value($this->entity->getBCEntity(), $this->field_name, $item);
       $this->drupalSetContent(drupal_render($output));
       $this->assertText($setting . '|' . $value['value'], format_string('Value @delta was displayed with expected setting.', array('@delta' => $delta)));
     }
@@ -175,8 +181,8 @@ function testFieldViewValue() {
     $setting = $display['settings']['test_formatter_setting_multiple'];
     $array = array();
     foreach ($this->values as $delta => $value) {
-      $item = $this->entity->{$this->field_name}[LANGUAGE_NOT_SPECIFIED][$delta];
-      $output = field_view_value($this->entity, $this->field_name, $item, $display);
+      $item = $this->entity->{$this->field_name}[$delta]->getValue();
+      $output = field_view_value($this->entity->getBCEntity(), $this->field_name, $item, $display);
       $this->drupalSetContent(drupal_render($output));
       $this->assertText($setting . '|0:' . $value['value'], format_string('Value @delta was displayed with expected setting.', array('@delta' => $delta)));
     }
@@ -191,8 +197,8 @@ function testFieldViewValue() {
     $setting = $display['settings']['test_formatter_setting_additional'];
     $array = array();
     foreach ($this->values as $delta => $value) {
-      $item = $this->entity->{$this->field_name}[LANGUAGE_NOT_SPECIFIED][$delta];
-      $output = field_view_value($this->entity, $this->field_name, $item, $display);
+      $item = $this->entity->{$this->field_name}[$delta]->getValue();
+      $output = field_view_value($this->entity->getBCEntity(), $this->field_name, $item, $display);
       $this->drupalSetContent(drupal_render($output));
       $this->assertText($setting . '|' . $value['value'] . '|' . ($value['value'] + 1), format_string('Value @delta was displayed with expected setting.', array('@delta' => $delta)));
     }
@@ -201,8 +207,8 @@ function testFieldViewValue() {
     // used.
     $setting = $this->display_options['teaser']['settings']['test_formatter_setting'];
     foreach ($this->values as $delta => $value) {
-      $item = $this->entity->{$this->field_name}[LANGUAGE_NOT_SPECIFIED][$delta];
-      $output = field_view_value($this->entity, $this->field_name, $item, 'teaser');
+      $item = $this->entity->{$this->field_name}[$delta]->getValue();
+      $output = field_view_value($this->entity->getBCEntity(), $this->field_name, $item, 'teaser');
       $this->drupalSetContent(drupal_render($output));
       $this->assertText($setting . '|' . $value['value'], format_string('Value @delta was displayed with expected setting.', array('@delta' => $delta)));
     }
@@ -211,8 +217,8 @@ function testFieldViewValue() {
     // are used.
     $setting = $this->display_options['default']['settings']['test_formatter_setting'];
     foreach ($this->values as $delta => $value) {
-      $item = $this->entity->{$this->field_name}[LANGUAGE_NOT_SPECIFIED][$delta];
-      $output = field_view_value($this->entity, $this->field_name, $item, 'unknown_view_mode');
+      $item = $this->entity->{$this->field_name}[$delta]->getValue();
+      $output = field_view_value($this->entity->getBCEntity(), $this->field_name, $item, 'unknown_view_mode');
       $this->drupalSetContent(drupal_render($output));
       $this->assertText($setting . '|' . $value['value'], format_string('Value @delta was displayed with expected setting.', array('@delta' => $delta)));
     }
diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldAccessTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldAccessTest.php
index bc1a380..86f1f34 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FieldAccessTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FieldAccessTest.php
@@ -64,7 +64,7 @@ function setUp() {
     $settings = array();
     $settings['type'] = $this->content_type;
     $settings['title'] = 'Field view access test';
-    $settings['test_view_field'] = array(LANGUAGE_NOT_SPECIFIED => array(array('value' => $this->test_view_field_value)));
+    $settings['test_view_field'] = array(array('value' => $this->test_view_field_value));
     $this->node = $this->drupalCreateNode($settings);
   }
 
diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php
index 89e07c6..0a44e18 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php
@@ -27,16 +27,16 @@ public static function getInfo() {
   function testFieldAttachView() {
     $this->createFieldWithInstance('_2');
 
-    $entity_type = 'test_entity';
-    $entity_init = field_test_create_entity();
+    $entity_type = 'entity_test';
+    $entity_init = entity_create('entity_test', array());
     $langcode = LANGUAGE_NOT_SPECIFIED;
     $options = array('field_name' => $this->field_name_2);
 
     // Populate values to be displayed.
     $values = $this->_generateTestFieldValues($this->field['cardinality']);
-    $entity_init->{$this->field_name}[$langcode] = $values;
+    $entity_init->{$this->field_name}->setValue($values);
     $values_2 = $this->_generateTestFieldValues($this->field_2['cardinality']);
-    $entity_init->{$this->field_name_2}[$langcode] = $values_2;
+    $entity_init->{$this->field_name_2}->setValue($values_2);
 
     // Simple formatter, label displayed.
     $entity = clone($entity_init);
@@ -64,9 +64,9 @@ function testFieldAttachView() {
     $display->setComponent($this->field_2['field_name'], $display_options_2);
 
     // View all fields.
-    field_attach_prepare_view($entity_type, array($entity->ftid => $entity), $displays);
-    $entity->content = field_attach_view($entity, $display);
-    $output = drupal_render($entity->content);
+    field_attach_prepare_view($entity_type, array($entity->ftid => $entity->getBCEntity()), $displays);
+    $content = field_attach_view($entity, $display);
+    $output = drupal_render($content);
     $this->content = $output;
     $this->assertRaw($this->instance['label'], "First field's label is displayed.");
     foreach ($values as $delta => $value) {
@@ -175,22 +175,22 @@ function testFieldAttachView() {
    * Tests the 'multiple entity' behavior of field_attach_prepare_view().
    */
   function testFieldAttachPrepareViewMultiple() {
-    $entity_type = 'test_entity';
+    $entity_type = 'entity_test';
     $langcode = LANGUAGE_NOT_SPECIFIED;
 
     // Set the instance to be hidden.
-    $display = entity_get_display('test_entity', 'test_bundle', 'full')
+    $display = entity_get_display('entity_test', 'entity_test', 'full')
       ->removeComponent($this->field['field_name']);
 
     // Set up a second instance on another bundle, with a formatter that uses
     // hook_field_formatter_prepare_view().
-    field_test_create_bundle('test_bundle_2');
+    entity_test_create_bundle('test_bundle_2');
     $formatter_setting = $this->randomName();
     $this->instance2 = $this->instance;
     $this->instance2['bundle'] = 'test_bundle_2';
     field_create_instance($this->instance2);
 
-    $display_2 = entity_get_display('test_entity', 'test_bundle_2', 'full')
+    $display_2 = entity_get_display('entity_test', 'test_bundle_2', 'full')
       ->setComponent($this->field['field_name'], array(
         'type' => 'field_test_with_prepare_view',
         'settings' => array(
@@ -198,21 +198,21 @@ function testFieldAttachPrepareViewMultiple() {
         ),
       ));
 
-    $displays = array('test_bundle' => $display, 'test_bundle_2' => $display_2);
+    $displays = array('entity_test' => $display, 'test_bundle_2' => $display_2);
 
     // Create one entity in each bundle.
-    $entity1_init = field_test_create_entity(1, 1, 'test_bundle');
+    $entity1_init = entity_create('entity_test', array('id' => 1, 'type' => 'entity_test'));
     $values1 = $this->_generateTestFieldValues($this->field['cardinality']);
-    $entity1_init->{$this->field_name}[$langcode] = $values1;
+    $entity1_init->{$this->field_name}->setValue($values1);
 
-    $entity2_init = field_test_create_entity(2, 2, 'test_bundle_2');
+    $entity2_init = entity_create('entity_test', array('id' => 2, 'type' => 'test_bundle_2'));
     $values2 = $this->_generateTestFieldValues($this->field['cardinality']);
-    $entity2_init->{$this->field_name}[$langcode] = $values2;
+    $entity2_init->{$this->field_name}->setValue($values2);
 
     // Run prepare_view, and check that the entities come out as expected.
     $entity1 = clone($entity1_init);
     $entity2 = clone($entity2_init);
-    $entities = array($entity1->ftid => $entity1, $entity2->ftid => $entity2);
+    $entities = array($entity1->id() => $entity1->getBCEntity(), $entity2->id() => $entity2->getBCEntity());
     field_attach_prepare_view($entity_type, $entities, $displays);
     $this->assertFalse(isset($entity1->{$this->field_name}[$langcode][0]['additional_formatter_value']), 'Entity 1 did not run through the prepare_view hook.');
     $this->assertTrue(isset($entity2->{$this->field_name}[$langcode][0]['additional_formatter_value']), 'Entity 2 ran through the prepare_view hook.');
@@ -236,7 +236,7 @@ function testFieldAttachCache() {
     $values = $this->_generateTestFieldValues($this->field['cardinality']);
 
     // Non-cacheable entity type.
-    $entity_type = 'test_entity';
+    $entity_type = 'entity_test';
     $cid = "field:$entity_type:{$entity_init->ftid}";
 
     // Check that no initial cache entry is present.
@@ -333,9 +333,8 @@ function testFieldAttachCache() {
   function testFieldAttachValidate() {
     $this->createFieldWithInstance('_2');
 
-    $entity_type = 'test_entity';
-    $entity = field_test_create_entity(0, 0, $this->instance['bundle']);
-    $langcode = LANGUAGE_NOT_SPECIFIED;
+    $entity_type = 'entity_test';
+    $entity = entity_create($entity_type, array('type' => $this->instance['bundle']));
 
     // Set up all but one values of the first field to generate errors.
     $values = array();
@@ -344,21 +343,22 @@ function testFieldAttachValidate() {
     }
     // Arrange for item 1 not to generate an error.
     $values[1]['value'] = 1;
-    $entity->{$this->field_name}[$langcode] = $values;
+    $entity->{$this->field_name}->value = 1;
 
     // Set up all values of the second field to generate errors.
     $values_2 = array();
     for ($delta = 0; $delta < $this->field_2['cardinality']; $delta++) {
       $values_2[$delta]['value'] = -1;
     }
-    $entity->{$this->field_name_2}[$langcode] = $values_2;
+    $entity->{$this->field_name_2}->setValue($values_2);
 
     // Validate all fields.
     try {
-      field_attach_validate($entity);
+      field_attach_validate($entity->getBCEntity());
     }
     catch (FieldValidationException $e) {
       $errors = $e->errors;
+      debug($errors);
     }
 
     foreach ($values as $delta => $value) {
@@ -425,7 +425,7 @@ function testFieldAttachValidate() {
   function testFieldAttachForm() {
     $this->createFieldWithInstance('_2');
 
-    $entity_type = 'test_entity';
+    $entity_type = 'entity_test';
     $entity = field_test_create_entity(0, 0, $this->instance['bundle']);
     $langcode = LANGUAGE_NOT_SPECIFIED;
 
@@ -465,7 +465,7 @@ function testFieldAttachForm() {
   function testFieldAttachExtractFormValues() {
     $this->createFieldWithInstance('_2');
 
-    $entity_type = 'test_entity';
+    $entity_type = 'entity_test';
     $entity_init = field_test_create_entity(0, 0, $this->instance['bundle']);
     $langcode = LANGUAGE_NOT_SPECIFIED;
 
diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldAttachStorageTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldAttachStorageTest.php
index 5ae3610..564dd55 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FieldAttachStorageTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FieldAttachStorageTest.php
@@ -35,52 +35,52 @@ function testFieldAttachSaveLoad() {
     field_update_instance($this->instance);
     $langcode = LANGUAGE_NOT_SPECIFIED;
 
-    $entity_type = 'test_entity';
+    $entity_type = 'entity_test';
     $values = array();
 
     // TODO : test empty values filtering and "compression" (store consecutive deltas).
 
     // Preparation: create three revisions and store them in $revision array.
     for ($revision_id = 0; $revision_id < 3; $revision_id++) {
-      $revision[$revision_id] = field_test_create_entity(0, $revision_id, $this->instance['bundle']);
+      $revision[$revision_id] = entity_create($entity_type, array('id' => 0, 'revision_id' => $revision_id));
       // Note: we try to insert one extra value.
       $values[$revision_id] = $this->_generateTestFieldValues($this->field['cardinality'] + 1);
       $current_revision = $revision_id;
       // If this is the first revision do an insert.
       if (!$revision_id) {
-        $revision[$revision_id]->{$this->field_name}[$langcode] = $values[$revision_id];
-        field_attach_insert($revision[$revision_id]);
+        $revision[$revision_id]->{$this->field_name}->setValue($values[$revision_id]);
+        field_attach_insert($revision[$revision_id]->getBCEntity());
       }
       else {
         // Otherwise do an update.
-        $revision[$revision_id]->{$this->field_name}[$langcode] = $values[$revision_id];
-        field_attach_update($revision[$revision_id]);
+        $revision[$revision_id]->{$this->field_name}->setValue($values[$revision_id]);
+        field_attach_update($revision[$revision_id]->getBCEntity());
       }
     }
 
     // Confirm current revision loads the correct data.
-    $entity = field_test_create_entity(0, 0, $this->instance['bundle']);
-    field_attach_load($entity_type, array(0 => $entity));
+    $entity = entity_create('entity_test', array('id' => 0, 'revision_id' => 0));
+    field_attach_load($entity_type, array(0 => $entity->getBCEntity()));
     // Number of values per field loaded equals the field cardinality.
-    $this->assertEqual(count($entity->{$this->field_name}[$langcode]), $this->field['cardinality'], 'Current revision: expected number of values');
+    $this->assertEqual(count($entity->{$this->field_name}), $this->field['cardinality'], 'Current revision: expected number of values');
     for ($delta = 0; $delta < $this->field['cardinality']; $delta++) {
       // The field value loaded matches the one inserted or updated.
-      $this->assertEqual($entity->{$this->field_name}[$langcode][$delta]['value'] , $values[$current_revision][$delta]['value'], format_string('Current revision: expected value %delta was found.', array('%delta' => $delta)));
+      $this->assertEqual($entity->{$this->field_name}[$delta]->value , $values[$current_revision][$delta]['value'], format_string('Current revision: expected value %delta was found.', array('%delta' => $delta)));
       // The value added in hook_field_load() is found.
-      $this->assertEqual($entity->{$this->field_name}[$langcode][$delta]['additional_key'], 'additional_value', format_string('Current revision: extra information for value %delta was found', array('%delta' => $delta)));
+      $this->assertEqual($entity->{$this->field_name}[$delta]->additional_key, 'additional_value', format_string('Current revision: extra information for value %delta was found', array('%delta' => $delta)));
     }
 
     // Confirm each revision loads the correct data.
     foreach (array_keys($revision) as $revision_id) {
-      $entity = field_test_create_entity(0, $revision_id, $this->instance['bundle']);
-      field_attach_load_revision($entity_type, array(0 => $entity));
+      $entity = entity_create('entity_test', array('id' => 0, 'revision_id' => $revision_id));
+      field_attach_load_revision($entity_type, array(0 => $entity->getBCEntity()));
       // Number of values per field loaded equals the field cardinality.
-      $this->assertEqual(count($entity->{$this->field_name}[$langcode]), $this->field['cardinality'], format_string('Revision %revision_id: expected number of values.', array('%revision_id' => $revision_id)));
+      $this->assertEqual(count($entity->{$this->field_name}), $this->field['cardinality'], format_string('Revision %revision_id: expected number of values.', array('%revision_id' => $revision_id)));
       for ($delta = 0; $delta < $this->field['cardinality']; $delta++) {
         // The field value loaded matches the one inserted or updated.
-        $this->assertEqual($entity->{$this->field_name}[$langcode][$delta]['value'], $values[$revision_id][$delta]['value'], format_string('Revision %revision_id: expected value %delta was found.', array('%revision_id' => $revision_id, '%delta' => $delta)));
+        $this->assertEqual($entity->{$this->field_name}[$delta]->value, $values[$revision_id][$delta]['value'], format_string('Revision %revision_id: expected value %delta was found.', array('%revision_id' => $revision_id, '%delta' => $delta)));
         // The value added in hook_field_load() is found.
-        $this->assertEqual($entity->{$this->field_name}[$langcode][$delta]['additional_key'], 'additional_value', format_string('Revision %revision_id: extra information for value %delta was found', array('%revision_id' => $revision_id, '%delta' => $delta)));
+        $this->assertEqual($entity->{$this->field_name}[$delta]->additional_key, 'additional_value', format_string('Revision %revision_id: extra information for value %delta was found', array('%revision_id' => $revision_id, '%delta' => $delta)));
       }
     }
   }
@@ -89,7 +89,7 @@ function testFieldAttachSaveLoad() {
    * Test the 'multiple' load feature.
    */
   function testFieldAttachLoadMultiple() {
-    $entity_type = 'test_entity';
+    $entity_type = 'entity_test';
     $langcode = LANGUAGE_NOT_SPECIFIED;
 
     // Define 2 bundles.
@@ -97,8 +97,8 @@ function testFieldAttachLoadMultiple() {
       1 => 'test_bundle_1',
       2 => 'test_bundle_2',
     );
-    field_test_create_bundle($bundles[1]);
-    field_test_create_bundle($bundles[2]);
+    entity_test_create_bundle($bundles[1]);
+    entity_test_create_bundle($bundles[2]);
     // Define 3 fields:
     // - field_1 is in bundle_1 and bundle_2,
     // - field_2 is in bundle_1,
@@ -116,7 +116,7 @@ function testFieldAttachLoadMultiple() {
       foreach ($field_bundles_map[$i] as $bundle) {
         $instance = array(
           'field_name' => $field_names[$i],
-          'entity_type' => 'test_entity',
+          'entity_type' => 'entity_test',
           'bundle' => $bundles[$bundle],
           'settings' => array(
             // Configure the instance so that we test hook_field_load()
@@ -130,14 +130,14 @@ function testFieldAttachLoadMultiple() {
 
     // Create one test entity per bundle, with random values.
     foreach ($bundles as $index => $bundle) {
-      $entities[$index] = field_test_create_entity($index, $index, $bundle);
+      $entities[$index] = entity_create('entity_test', array('id' => $index, 'revision_id' => $index));
       $entity = clone($entities[$index]);
-      $instances = field_info_instances('test_entity', $bundle);
+      $instances = field_info_instances('entity_test', $bundle);
       foreach ($instances as $field_name => $instance) {
         $values[$index][$field_name] = mt_rand(1, 127);
-        $entity->$field_name = array($langcode => array(array('value' => $values[$index][$field_name])));
+        $entity->$field_name->setValue(array('value' => $values[$index][$field_name]));
       }
-      field_attach_insert($entity);
+      field_attach_insert($entity->getBCEntity());
     }
 
     // Check that a single load correctly loads field values for both entities.
@@ -146,9 +146,9 @@ function testFieldAttachLoadMultiple() {
       $instances = field_info_instances($entity_type, $bundles[$index]);
       foreach ($instances as $field_name => $instance) {
         // The field value loaded matches the one inserted.
-        $this->assertEqual($entity->{$field_name}[$langcode][0]['value'], $values[$index][$field_name], format_string('Entity %index: expected value was found.', array('%index' => $index)));
+        $this->assertEqual($entity->{$field_name}->value, $values[$index][$field_name], format_string('Entity %index: expected value was found.', array('%index' => $index)));
         // The value added in hook_field_load() is found.
-        $this->assertEqual($entity->{$field_name}[$langcode][0]['additional_key'], 'additional_value', format_string('Entity %index: extra information was found', array('%index' => $index)));
+        $this->assertEqual($entity->{$field_name}->additional_key, 'additional_value', format_string('Entity %index: extra information was found', array('%index' => $index)));
       }
     }
 
@@ -165,7 +165,7 @@ function testFieldAttachLoadMultiple() {
    * Test saving and loading fields using different storage backends.
    */
   function testFieldAttachSaveLoadDifferentStorage() {
-    $entity_type = 'test_entity';
+    $entity_type = 'entity_test';
     $langcode = LANGUAGE_NOT_SPECIFIED;
 
     // Create two fields using different storage backends, and their instances.
@@ -187,8 +187,8 @@ function testFieldAttachSaveLoadDifferentStorage() {
       field_create_field($field);
       $instance = array(
         'field_name' => $field['field_name'],
-        'entity_type' => 'test_entity',
-        'bundle' => 'test_bundle',
+        'entity_type' => 'entity_test',
+        'bundle' => 'entity_test',
       );
       field_create_instance($instance);
     }
@@ -228,8 +228,8 @@ function testFieldStorageDetailsAlter() {
     $field = field_create_field($field);
     $instance = array(
       'field_name' => $field_name,
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle',
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
     );
     field_create_instance($instance);
 
@@ -258,7 +258,7 @@ function testFieldStorageDetailsAlter() {
    * Tests insert and update with missing or NULL fields.
    */
   function testFieldAttachSaveMissingData() {
-    $entity_type = 'test_entity';
+    $entity_type = 'entity_test';
     $entity_init = field_test_create_entity();
     $langcode = LANGUAGE_NOT_SPECIFIED;
 
@@ -341,7 +341,7 @@ function testFieldAttachSaveMissingDataDefaultValue() {
     field_update_instance($this->instance);
 
     // Verify that fields are populated with default values.
-    $entity_type = 'test_entity';
+    $entity_type = 'entity_test';
     $entity_init = field_test_create_entity();
     $langcode = LANGUAGE_NOT_SPECIFIED;
     $default = field_test_default_value($entity_init, $this->field, $this->instance);
@@ -369,7 +369,7 @@ function testFieldAttachSaveMissingDataDefaultValue() {
 
     // Verify that prepopulated field values are not overwritten by defaults.
     $value = array(array('value' => $default[0]['value'] - mt_rand(1, 127)));
-    $entity = entity_create('test_entity', array('fttype' => $entity_init->bundle(), $this->field_name => array($langcode => $value)));
+    $entity = entity_create('entity_test', array('fttype' => $entity_init->bundle(), $this->field_name => array($langcode => $value)));
     $this->assertEqual($entity->{$this->field_name}[$langcode], $value, 'Prepopulated field value correctly maintained.');
   }
 
@@ -377,7 +377,7 @@ function testFieldAttachSaveMissingDataDefaultValue() {
    * Test field_attach_delete().
    */
   function testFieldAttachDelete() {
-    $entity_type = 'test_entity';
+    $entity_type = 'entity_test';
     $langcode = LANGUAGE_NOT_SPECIFIED;
     $rev[0] = field_test_create_entity(0, 0, $this->instance['bundle']);
 
@@ -434,7 +434,7 @@ function testFieldAttachDelete() {
   function testFieldAttachCreateRenameBundle() {
     // Create a new bundle.
     $new_bundle = 'test_bundle_' . drupal_strtolower($this->randomName());
-    field_test_create_bundle($new_bundle);
+    entity_test_create_bundle($new_bundle);
 
     // Add an instance to that bundle.
     $this->instance['bundle'] = $new_bundle;
@@ -445,7 +445,7 @@ function testFieldAttachCreateRenameBundle() {
     $langcode = LANGUAGE_NOT_SPECIFIED;
     $values = $this->_generateTestFieldValues($this->field['cardinality']);
     $entity->{$this->field_name}[$langcode] = $values;
-    $entity_type = 'test_entity';
+    $entity_type = 'entity_test';
     field_attach_insert($entity);
 
     // Verify the field data is present on load.
@@ -473,7 +473,7 @@ function testFieldAttachCreateRenameBundle() {
   function testFieldAttachDeleteBundle() {
     // Create a new bundle.
     $new_bundle = 'test_bundle_' . drupal_strtolower($this->randomName());
-    field_test_create_bundle($new_bundle);
+    entity_test_create_bundle($new_bundle);
 
     // Add an instance to that bundle.
     $this->instance['bundle'] = $new_bundle;
@@ -485,7 +485,7 @@ function testFieldAttachDeleteBundle() {
     field_create_field($field);
     $instance = array(
       'field_name' => $field_name,
-      'entity_type' => 'test_entity',
+      'entity_type' => 'entity_test',
       'bundle' => $this->instance['bundle'],
       'label' => $this->randomName() . '_label',
       'description' => $this->randomName() . '_description',
@@ -507,7 +507,7 @@ function testFieldAttachDeleteBundle() {
 
     // Verify the fields are present on load
     $entity = field_test_create_entity(0, 0, $this->instance['bundle']);
-    field_attach_load('test_entity', array(0 => $entity));
+    field_attach_load('entity_test', array(0 => $entity));
     $this->assertEqual(count($entity->{$this->field_name}[$langcode]), 4, 'First field got loaded');
     $this->assertEqual(count($entity->{$field_name}[$langcode]), 1, 'Second field got loaded');
 
@@ -516,12 +516,12 @@ function testFieldAttachDeleteBundle() {
 
     // Verify no data gets loaded
     $entity = field_test_create_entity(0, 0, $this->instance['bundle']);
-    field_attach_load('test_entity', array(0 => $entity));
+    field_attach_load('entity_test', array(0 => $entity));
     $this->assertFalse(isset($entity->{$this->field_name}[$langcode]), 'No data for first field');
     $this->assertFalse(isset($entity->{$field_name}[$langcode]), 'No data for second field');
 
     // Verify that the instances are gone
-    $this->assertFalse(field_read_instance('test_entity', $this->field_name, $this->instance['bundle']), "First field is deleted");
-    $this->assertFalse(field_read_instance('test_entity', $field_name, $instance['bundle']), "Second field is deleted");
+    $this->assertFalse(field_read_instance('entity_test', $this->field_name, $this->instance['bundle']), "First field is deleted");
+    $this->assertFalse(field_read_instance('entity_test', $field_name, $instance['bundle']), "Second field is deleted");
   }
 }
diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldAttachTestBase.php b/core/modules/field/lib/Drupal/field/Tests/FieldAttachTestBase.php
index 9d15ba2..203650e 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FieldAttachTestBase.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FieldAttachTestBase.php
@@ -14,7 +14,7 @@
    *
    * @var array
    */
-  public static $modules = array('field_test');
+  public static $modules = array('field_test', 'entity_test');
 
   function setUp() {
     parent::setUp();
@@ -41,8 +41,8 @@ function createFieldWithInstance($suffix = '') {
     $this->$field_id = $this->{$field}['id'];
     $this->$instance = array(
       'field_name' => $this->$field_name,
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle',
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
       'label' => $this->randomName() . '_label',
       'description' => $this->randomName() . '_description',
       'weight' => mt_rand(0, 127),
diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldInfoTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldInfoTest.php
index 3115851..efdf7b9 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FieldInfoTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FieldInfoTest.php
@@ -53,11 +53,11 @@ function testFieldInfo() {
     }
 
     // Verify that no unexpected instances exist.
-    $instances = field_info_instances('test_entity');
+    $instances = field_info_instances('entity_test');
     $expected = array();
-    $this->assertIdentical($instances, $expected, format_string("field_info_instances('test_entity') returns %expected.", array('%expected' => var_export($expected, TRUE))));
-    $instances = field_info_instances('test_entity', 'test_bundle');
-    $this->assertIdentical($instances, array(), "field_info_instances('test_entity', 'test_bundle') returns an empty array.");
+    $this->assertIdentical($instances, $expected, format_string("field_info_instances('entity_test') returns %expected.", array('%expected' => var_export($expected, TRUE))));
+    $instances = field_info_instances('entity_test', 'entity_test');
+    $this->assertIdentical($instances, array(), "field_info_instances('entity_test', 'entity_test') returns an empty array.");
 
     // Create a field, verify it shows up.
     $core_fields = field_info_fields();
@@ -81,8 +81,8 @@ function testFieldInfo() {
     // Create an instance, verify that it shows up
     $instance = array(
       'field_name' => $field['field_name'],
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle',
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
       'label' => $this->randomName(),
       'description' => $this->randomName(),
       'weight' => mt_rand(0, 127),
@@ -93,20 +93,20 @@ function testFieldInfo() {
           'test_setting' => 999)));
     field_create_instance($instance);
 
-    $info = entity_get_info('test_entity');
-    $instances = field_info_instances('test_entity', $instance['bundle']);
+    $info = entity_get_info('entity_test');
+    $instances = field_info_instances('entity_test', $instance['bundle']);
     $this->assertEqual(count($instances), 1, format_string('One instance shows up in info when attached to a bundle on a @label.', array(
       '@label' => $info['label']
     )));
     $this->assertTrue($instance < $instances[$instance['field_name']], 'Instance appears in info correctly');
 
     // Test a valid entity type but an invalid bundle.
-    $instances = field_info_instances('test_entity', 'invalid_bundle');
-    $this->assertIdentical($instances, array(), "field_info_instances('test_entity', 'invalid_bundle') returns an empty array.");
+    $instances = field_info_instances('entity_test', 'invalid_bundle');
+    $this->assertIdentical($instances, array(), "field_info_instances('entity_test', 'invalid_bundle') returns an empty array.");
 
     // Test invalid entity type and bundle.
     $instances = field_info_instances('invalid_entity', $instance['bundle']);
-    $this->assertIdentical($instances, array(), "field_info_instances('invalid_entity', 'test_bundle') returns an empty array.");
+    $this->assertIdentical($instances, array(), "field_info_instances('invalid_entity', 'entity_test') returns an empty array.");
 
     // Test invalid entity type, no bundle provided.
     $instances = field_info_instances('invalid_entity');
@@ -172,8 +172,8 @@ function testInstancePrepare() {
     field_create_field($field_definition);
     $instance_definition = array(
       'field_name' => $field_definition['field_name'],
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle',
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
     );
     field_create_instance($instance_definition);
 
@@ -237,8 +237,8 @@ function testFieldMap() {
     // We will overlook fields created by the 'standard' installation profile.
     $exclude = field_info_field_map();
 
-    // Create a new bundle for 'test_entity' entity type.
-    field_test_create_bundle('test_bundle_2');
+    // Create a new bundle for 'entity_test' entity type.
+    entity_test_create_bundle('test_bundle_2');
 
     // Create a couple fields.
     $fields  = array(
@@ -259,23 +259,23 @@ function testFieldMap() {
     $instances = array(
       array(
         'field_name' => 'field_1',
-        'entity_type' => 'test_entity',
-        'bundle' => 'test_bundle',
+        'entity_type' => 'entity_test',
+        'bundle' => 'entity_test',
       ),
       array(
         'field_name' => 'field_1',
-        'entity_type' => 'test_entity',
+        'entity_type' => 'entity_test',
         'bundle' => 'test_bundle_2',
       ),
       array(
         'field_name' => 'field_2',
-        'entity_type' => 'test_entity',
-        'bundle' => 'test_bundle',
+        'entity_type' => 'entity_test',
+        'bundle' => 'entity_test',
       ),
       array(
         'field_name' => 'field_2',
         'entity_type' => 'test_cacheable_entity',
-        'bundle' => 'test_bundle',
+        'bundle' => 'entity_test',
       ),
     );
     foreach ($instances as $instance) {
@@ -286,14 +286,14 @@ function testFieldMap() {
       'field_1' => array(
         'type' => 'test_field',
         'bundles' => array(
-          'test_entity' => array('test_bundle', 'test_bundle_2'),
+          'entity_test' => array('entity_test', 'test_bundle_2'),
         ),
       ),
       'field_2' => array(
         'type' => 'hidden_test_field',
         'bundles' => array(
-          'test_entity' => array('test_bundle'),
-          'test_cacheable_entity' => array('test_bundle'),
+          'entity_test' => array('entity_test'),
+          'test_cacheable_entity' => array('entity_test'),
         ),
       ),
     );
diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldInstanceCrudTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldInstanceCrudTest.php
index 90fcc05..b5620ce 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FieldInstanceCrudTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FieldInstanceCrudTest.php
@@ -38,8 +38,8 @@ function setUp() {
     field_create_field($this->field);
     $this->instance_definition = array(
       'field_name' => $this->field['field_name'],
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle',
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
     );
   }
 
@@ -138,7 +138,7 @@ function testReadFieldInstance() {
     field_create_instance($this->instance_definition);
 
     // Read the instance back.
-    $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
+    $instance = field_read_instance('entity_test', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
     $this->assertTrue($this->instance_definition == $instance, 'The field was properly read.');
   }
 
@@ -149,7 +149,7 @@ function testUpdateFieldInstance() {
     field_create_instance($this->instance_definition);
 
     // Check that basic changes are saved.
-    $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
+    $instance = field_read_instance('entity_test', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
     $instance['required'] = !$instance['required'];
     $instance['label'] = $this->randomName();
     $instance['description'] = $this->randomName();
@@ -158,7 +158,7 @@ function testUpdateFieldInstance() {
     $instance['widget']['weight']++;
     field_update_instance($instance);
 
-    $instance_new = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
+    $instance_new = field_read_instance('entity_test', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
     $this->assertEqual($instance['required'], $instance_new['required'], '"required" change is saved');
     $this->assertEqual($instance['label'], $instance_new['label'], '"label" change is saved');
     $this->assertEqual($instance['description'], $instance_new['description'], '"description" change is saved');
@@ -166,11 +166,11 @@ function testUpdateFieldInstance() {
     $this->assertEqual($instance['widget']['weight'], $instance_new['widget']['weight'], 'Widget weight change is saved');
 
     // Check that changing the widget type updates the default settings.
-    $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
+    $instance = field_read_instance('entity_test', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
     $instance['widget']['type'] = 'test_field_widget_multiple';
     field_update_instance($instance);
 
-    $instance_new = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
+    $instance_new = field_read_instance('entity_test', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
     $this->assertEqual($instance['widget']['type'], $instance_new['widget']['type'] , 'Widget type change is saved.');
     $settings = field_info_widget_settings($instance_new['widget']['type']);
     $this->assertIdentical($settings, array_intersect_key($instance_new['widget']['settings'], $settings) , 'Widget type change updates default settings.');
@@ -194,21 +194,21 @@ function testDeleteFieldInstance() {
     $instance = field_create_instance($this->another_instance_definition);
 
     // Test that the first instance is not deleted, and then delete it.
-    $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle'], array('include_deleted' => TRUE));
+    $instance = field_read_instance('entity_test', $this->instance_definition['field_name'], $this->instance_definition['bundle'], array('include_deleted' => TRUE));
     $this->assertTrue(!empty($instance) && empty($instance['deleted']), 'A new field instance is not marked for deletion.');
     field_delete_instance($instance);
 
     // Make sure the instance is marked as deleted when the instance is
     // specifically loaded.
-    $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle'], array('include_deleted' => TRUE));
+    $instance = field_read_instance('entity_test', $this->instance_definition['field_name'], $this->instance_definition['bundle'], array('include_deleted' => TRUE));
     $this->assertTrue(!empty($instance['deleted']), 'A deleted field instance is marked for deletion.');
 
     // Try to load the instance normally and make sure it does not show up.
-    $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
+    $instance = field_read_instance('entity_test', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
     $this->assertTrue(empty($instance), 'A deleted field instance is not loaded by default.');
 
     // Make sure the other field instance is not deleted.
-    $another_instance = field_read_instance('test_entity', $this->another_instance_definition['field_name'], $this->another_instance_definition['bundle']);
+    $another_instance = field_read_instance('entity_test', $this->another_instance_definition['field_name'], $this->another_instance_definition['bundle']);
     $this->assertTrue(!empty($another_instance) && empty($another_instance['deleted']), 'A non-deleted field instance is not marked for deletion.');
 
     // Make sure the field is deleted when its last instance is deleted.
diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldTestBase.php b/core/modules/field/lib/Drupal/field/Tests/FieldTestBase.php
index a34586e..d473584 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FieldTestBase.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FieldTestBase.php
@@ -61,8 +61,9 @@ function _generateTestFieldValues($cardinality) {
    */
   function assertFieldValues(EntityInterface $entity, $field_name, $langcode, $expected_values, $column = 'value') {
     $e = clone $entity;
-    field_attach_load('test_entity', array($e->ftid => $e));
-    $values = isset($e->{$field_name}[$langcode]) ? $e->{$field_name}[$langcode] : array();
+    $bc_entity = $e->getBCEntity();
+    field_attach_load('entity_test', array($e->id() => $bc_entity));
+    $values = isset($bc_entity->{$field_name}[$langcode]) ? $bc_entity->{$field_name}[$langcode] : array();
     $this->assertEqual(count($values), count($expected_values), 'Expected number of values were saved.');
     foreach ($expected_values as $key => $value) {
       $this->assertEqual($values[$key][$column], $value, format_string('Value @value was saved correctly.', array('@value' => $value)));
diff --git a/core/modules/field/lib/Drupal/field/Tests/FormTest.php b/core/modules/field/lib/Drupal/field/Tests/FormTest.php
index 2f5dbee..aefbd34 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FormTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FormTest.php
@@ -14,7 +14,7 @@ class FormTest extends FieldTestBase {
    *
    * @var array
    */
-  public static $modules = array('node', 'field_test', 'options');
+  public static $modules = array('node', 'field_test', 'options', 'entity_test');
 
   public static function getInfo() {
     return array(
@@ -27,7 +27,7 @@ public static function getInfo() {
   function setUp() {
     parent::setUp();
 
-    $web_user = $this->drupalCreateUser(array('access field_test content', 'administer field_test content'));
+    $web_user = $this->drupalCreateUser(array('view test entity', 'administer entity_test content'));
     $this->drupalLogin($web_user);
 
     $this->field_single = array('field_name' => 'field_single', 'type' => 'test_field');
@@ -35,8 +35,8 @@ function setUp() {
     $this->field_unlimited = array('field_name' => 'field_unlimited', 'type' => 'test_field', 'cardinality' => FIELD_CARDINALITY_UNLIMITED);
 
     $this->instance = array(
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle',
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
       'label' => $this->randomName() . '_label',
       'description' => '[site:name]_description',
       'weight' => mt_rand(0, 127),
@@ -62,7 +62,7 @@ function testFieldFormSingle() {
     $langcode = LANGUAGE_NOT_SPECIFIED;
 
     // Display creation form.
-    $this->drupalGet('test-entity/add/test_bundle');
+    $this->drupalGet('entity_test/add');
 
     // Create token value expected for description.
     $token_description = check_plain(variable_get('site_name', 'Drupal')) . '_description';
@@ -75,43 +75,59 @@ function testFieldFormSingle() {
     $this->assertNoText('From hook_field_widget_form_alter(): Default form is true.', 'Not default value form in hook_field_widget_form_alter().');
 
     // Submit with invalid value (field-level validation).
-    $edit = array("{$this->field_name}[$langcode][0][value]" => -1);
+    $edit = array(
+      'user_id' => 1,
+      'name' => $this->randomName(),
+      "{$this->field_name}[$langcode][0][value]" => -1
+    );
     $this->drupalPost(NULL, $edit, t('Save'));
     $this->assertRaw(t('%name does not accept the value -1.', array('%name' => $this->instance['label'])), 'Field validation fails with invalid input.');
     // TODO : check that the correct field is flagged for error.
 
     // Create an entity
     $value = mt_rand(1, 127);
-    $edit = array("{$this->field_name}[$langcode][0][value]" => $value);
+    $edit = array(
+      'user_id' => 1,
+      'name' => $this->randomName(),
+      "{$this->field_name}[$langcode][0][value]" => $value,
+    );
     $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
+    preg_match('|entity_test/manage/(\d+)/edit|', $this->url, $match);
     $id = $match[1];
-    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created');
-    $entity = field_test_entity_test_load($id);
-    $this->assertEqual($entity->{$this->field_name}[$langcode][0]['value'], $value, 'Field value was saved');
+    $this->assertText(t('entity_test @id has been created.', array('@id' => $id)), 'Entity was created');
+    $entity = entity_load('entity_test', $id);
+    $this->assertEqual($entity->{$this->field_name}->value, $value, 'Field value was saved');
 
     // Display edit form.
-    $this->drupalGet('test-entity/manage/' . $id . '/edit');
+    $this->drupalGet('entity_test/manage/' . $id . '/edit');
     $this->assertFieldByName("{$this->field_name}[$langcode][0][value]", $value, 'Widget is displayed with the correct default value');
     $this->assertNoField("{$this->field_name}[$langcode][1][value]", 'No extraneous widget is displayed');
 
     // Update the entity.
     $value = mt_rand(1, 127);
-    $edit = array("{$this->field_name}[$langcode][0][value]" => $value);
+    $edit = array(
+      'user_id' => 1,
+      'name' => $this->randomName(),
+      "{$this->field_name}[$langcode][0][value]" => $value,
+    );
     $this->drupalPost(NULL, $edit, t('Save'));
-    $this->assertRaw(t('test_entity @id has been updated.', array('@id' => $id)), 'Entity was updated');
-    $this->container->get('plugin.manager.entity')->getStorageController('test_entity')->resetCache(array($id));
-    $entity = field_test_entity_test_load($id);
-    $this->assertEqual($entity->{$this->field_name}[$langcode][0]['value'], $value, 'Field value was updated');
+    $this->assertText(t('entity_test @id has been updated.', array('@id' => $id)), 'Entity was updated');
+    $this->container->get('plugin.manager.entity')->getStorageController('entity_test')->resetCache(array($id));
+    $entity = entity_load('entity_test', $id);
+    $this->assertEqual($entity->{$this->field_name}->value, $value, 'Field value was updated');
 
     // Empty the field.
     $value = '';
-    $edit = array("{$this->field_name}[$langcode][0][value]" => $value);
-    $this->drupalPost('test-entity/manage/' . $id . '/edit', $edit, t('Save'));
-    $this->assertRaw(t('test_entity @id has been updated.', array('@id' => $id)), 'Entity was updated');
-    $this->container->get('plugin.manager.entity')->getStorageController('test_entity')->resetCache(array($id));
-    $entity = field_test_entity_test_load($id);
-    $this->assertIdentical($entity->{$this->field_name}, array(), 'Field was emptied');
+    $edit = array(
+      'user_id' => 1,
+      'name' => $this->randomName(),
+      "{$this->field_name}[$langcode][0][value]" => $value
+    );
+    $this->drupalPost('entity_test/manage/' . $id . '/edit', $edit, t('Save'));
+    $this->assertText(t('entity_test @id has been updated.', array('@id' => $id)), 'Entity was updated');
+    $this->container->get('plugin.manager.entity')->getStorageController('entity_test')->resetCache(array($id));
+    $entity = entity_load('entity_test', $id);
+    $this->assertTrue($entity->{$this->field_name}->isEmpty(), 'Field was emptied');
   }
 
   /**
@@ -128,18 +144,22 @@ function testFieldFormDefaultValue() {
     $langcode = LANGUAGE_NOT_SPECIFIED;
 
     // Display creation form.
-    $this->drupalGet('test-entity/add/test_bundle');
+    $this->drupalGet('entity_test/add');
     // Test that the default value is displayed correctly.
     $this->assertFieldByXpath("//input[@name='{$this->field_name}[$langcode][0][value]' and @value='$default']");
 
     // Try to submit an empty value.
-    $edit = array("{$this->field_name}[$langcode][0][value]" => '');
+    $edit = array(
+      'user_id' => 1,
+      'name' => $this->randomName(),
+      "{$this->field_name}[$langcode][0][value]" => '',
+    );
     $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
+    preg_match('|entity_test/manage/(\d+)/edit|', $this->url, $match);
     $id = $match[1];
-    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created.');
-    $entity = field_test_entity_test_load($id);
-    $this->assertTrue(empty($entity->{$this->field_name}), 'Field is now empty.');
+    $this->assertText(t('entity_test @id has been created.', array('@id' => $id)), 'Entity was created.');
+    $entity = entity_load('entity_test', $id);
+    $this->assertTrue($entity->{$this->field_name}->isEmpty(), 'Field is now empty.');
   }
 
   function testFieldFormSingleRequired() {
@@ -153,23 +173,31 @@ function testFieldFormSingleRequired() {
 
     // Submit with missing required value.
     $edit = array();
-    $this->drupalPost('test-entity/add/test_bundle', $edit, t('Save'));
+    $this->drupalPost('entity_test/add', $edit, t('Save'));
     $this->assertRaw(t('!name field is required.', array('!name' => $this->instance['label'])), 'Required field with no value fails validation');
 
     // Create an entity
     $value = mt_rand(1, 127);
-    $edit = array("{$this->field_name}[$langcode][0][value]" => $value);
+    $edit = array(
+      'user_id' => 1,
+      'name' => $this->randomName(),
+      "{$this->field_name}[$langcode][0][value]" => $value,
+    );
     $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
+    preg_match('|entity_test/manage/(\d+)/edit|', $this->url, $match);
     $id = $match[1];
-    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created');
-    $entity = field_test_entity_test_load($id);
-    $this->assertEqual($entity->{$this->field_name}[$langcode][0]['value'], $value, 'Field value was saved');
+    $this->assertText(t('entity_test @id has been created.', array('@id' => $id)), 'Entity was created');
+    $entity = entity_load('entity_test', $id);
+    $this->assertEqual($entity->{$this->field_name}->value, $value, 'Field value was saved');
 
     // Edit with missing required value.
     $value = '';
-    $edit = array("{$this->field_name}[$langcode][0][value]" => $value);
-    $this->drupalPost('test-entity/manage/' . $id . '/edit', $edit, t('Save'));
+    $edit = array(
+      'user_id' => 1,
+      'name' => $this->randomName(),
+      "{$this->field_name}[$langcode][0][value]" => $value,
+    );
+    $this->drupalPost('entity_test/manage/' . $id . '/edit', $edit, t('Save'));
     $this->assertRaw(t('!name field is required.', array('!name' => $this->instance['label'])), 'Required field with no value fails validation');
   }
 
@@ -190,7 +218,7 @@ function testFieldFormUnlimited() {
     $langcode = LANGUAGE_NOT_SPECIFIED;
 
     // Display creation form -> 1 widget.
-    $this->drupalGet('test-entity/add/test_bundle');
+    $this->drupalGet('entity_test/add');
     $this->assertFieldByName("{$this->field_name}[$langcode][0][value]", '', 'Widget 1 is displayed');
     $this->assertNoField("{$this->field_name}[$langcode][1][value]", 'No extraneous widget is displayed');
 
@@ -207,7 +235,11 @@ function testFieldFormUnlimited() {
     // Prepare values and weights.
     $count = 3;
     $delta_range = $count - 1;
-    $values = $weights = $pattern = $expected_values = $edit = array();
+    $values = $weights = $pattern = $expected_values = array();
+    $edit = array(
+      'user_id' => 1,
+      'name' => $this->randomName(),
+    );
     for ($delta = 0; $delta <= $delta_range; $delta++) {
       // Assign unique random values and weights.
       do {
@@ -222,6 +254,7 @@ function testFieldFormUnlimited() {
       $values[$delta] = $value;
       $weights[$delta] = $weight;
       $field_values[$weight]['value'] = (string) $value;
+      $field_values[$weight]['additional_key'] = NULL;
       $pattern[$weight] = "<input [^>]*value=\"$value\" [^>]*";
     }
 
@@ -240,13 +273,13 @@ function testFieldFormUnlimited() {
 
     // Submit the form and create the entity.
     $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
+    preg_match('|entity_test/manage/(\d+)/edit|', $this->url, $match);
     $id = $match[1];
-    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created');
-    $entity = field_test_entity_test_load($id);
+    $this->assertText(t('entity_test @id has been created.', array('@id' => $id)), 'Entity was created');
+    $entity = entity_load('entity_test', $id);
     ksort($field_values);
     $field_values = array_values($field_values);
-    $this->assertIdentical($entity->{$this->field_name}[$langcode], $field_values, 'Field values were saved in the correct order');
+    $this->assertIdentical($entity->{$this->field_name}->getValue(), $field_values, 'Field values were saved in the correct order');
 
     // Display edit form: check that the expected number of widgets is
     // displayed, with correct values change values, reorder, leave an empty
@@ -279,8 +312,8 @@ function testFieldFormMultivalueWithRequiredRadio() {
     ));
     $instance = array(
       'field_name' => 'required_radio_test',
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle',
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
       'required' => TRUE,
       'widget' => array(
         'type' => 'options_buttons',
@@ -289,7 +322,7 @@ function testFieldFormMultivalueWithRequiredRadio() {
     field_create_instance($instance);
 
     // Display creation form.
-    $this->drupalGet('test-entity/add/test_bundle');
+    $this->drupalGet('entity_test/add');
 
     // Press the 'Add more' button.
     $this->drupalPost(NULL, array(), t('Add another item'));
@@ -312,7 +345,7 @@ function testFieldFormJSAddMore() {
     $langcode = LANGUAGE_NOT_SPECIFIED;
 
     // Display creation form -> 1 widget.
-    $this->drupalGet('test-entity/add/test_bundle');
+    $this->drupalGet('entity_test/add');
 
     // Press 'add more' button a couple times -> 3 widgets.
     // drupalPostAJAX() will not work iteratively, so we add those through
@@ -372,21 +405,25 @@ function testFieldFormMultipleWidget() {
     $langcode = LANGUAGE_NOT_SPECIFIED;
 
     // Display creation form.
-    $this->drupalGet('test-entity/add/test_bundle');
+    $this->drupalGet('entity_test/add');
     $this->assertFieldByName("{$this->field_name}[$langcode]", '', 'Widget is displayed.');
 
     // Create entity with three values.
-    $edit = array("{$this->field_name}[$langcode]" => '1, 2, 3');
+    $edit = array(
+      'user_id' => 1,
+      'name' => $this->randomName(),
+      "{$this->field_name}[$langcode]" => '1, 2, 3',
+    );
     $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
+    preg_match('|entity_test/manage/(\d+)/edit|', $this->url, $match);
     $id = $match[1];
 
     // Check that the values were saved.
-    $entity_init = field_test_create_entity($id);
+    $entity_init = entity_load('entity_test', $id);
     $this->assertFieldValues($entity_init, $this->field_name, $langcode, array(1, 2, 3));
 
     // Display the form, check that the values are correctly filled in.
-    $this->drupalGet('test-entity/manage/' . $id . '/edit');
+    $this->drupalGet('entity_test/manage/' . $id . '/edit');
     $this->assertFieldByName("{$this->field_name}[$langcode]", '1, 2, 3', 'Widget is displayed.');
 
     // Submit the form with more values than the field accepts.
@@ -404,8 +441,11 @@ function testFieldFormAccess() {
     // Create a "regular" field.
     $field = $this->field_single;
     $field_name = $field['field_name'];
+    $entity_type = 'entity_test_rev';
     $instance = $this->instance;
     $instance['field_name'] = $field_name;
+    $instance['entity_type'] = $entity_type;
+    $instance['bundle'] = $entity_type;
     field_create_field($field);
     field_create_instance($instance);
 
@@ -417,8 +457,8 @@ function testFieldFormAccess() {
     $field_name_no_access = $field_no_access['field_name'];
     $instance_no_access = array(
       'field_name' => $field_name_no_access,
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle',
+      'entity_type' => $entity_type,
+      'bundle' => $entity_type,
       'default_value' => array(0 => array('value' => 99)),
     );
     field_create_field($field_no_access);
@@ -428,52 +468,60 @@ function testFieldFormAccess() {
 
     // Test that the form structure includes full information for each delta
     // apart from #access.
-    $entity_type = 'test_entity';
-    $entity = field_test_create_entity(0, 0, $this->instance['bundle']);
+    $entity = entity_create($entity_type, array('id' => 0, 'revision_id' => 0));
 
     $form = array();
     $form_state = form_state_defaults();
-    field_attach_form($entity, $form, $form_state);
+    field_attach_form($entity->getBCEntity(), $form, $form_state);
 
     $this->assertEqual($form[$field_name_no_access][$langcode][0]['value']['#entity_type'], $entity_type, 'The correct entity type is set in the field structure.');
     $this->assertFalse($form[$field_name_no_access]['#access'], 'Field #access is FALSE for the field without edit access.');
 
     // Display creation form.
-    $this->drupalGet('test-entity/add/test_bundle');
+    $this->drupalGet($entity_type . '/add');
     $this->assertNoFieldByName("{$field_name_no_access}[$langcode][0][value]", '', 'Widget is not displayed if field access is denied.');
 
     // Create entity.
-    $edit = array("{$field_name}[$langcode][0][value]" => 1);
+    $edit = array(
+      'user_id' => 1,
+      'name' => $this->randomName(),
+      "{$field_name}[$langcode][0][value]" => 1,
+    );
     $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
+    preg_match("|$entity_type/manage/(\d+)/edit|", $this->url, $match);
     $id = $match[1];
 
     // Check that the default value was saved.
-    $entity = field_test_entity_test_load($id);
-    $this->assertEqual($entity->{$field_name_no_access}[$langcode][0]['value'], 99, 'Default value was saved for the field with no edit access.');
-    $this->assertEqual($entity->{$field_name}[$langcode][0]['value'], 1, 'Entered value vas saved for the field with edit access.');
+    $entity = entity_load($entity_type, $id);
+    $this->assertEqual($entity->$field_name_no_access->value, 99, 'Default value was saved for the field with no edit access.');
+    $this->assertEqual($entity->$field_name->value, 1, 'Entered value vas saved for the field with edit access.');
 
     // Create a new revision.
-    $edit = array("{$field_name}[$langcode][0][value]" => 2, 'revision' => TRUE);
-    $this->drupalPost('test-entity/manage/' . $id . '/edit', $edit, t('Save'));
+    $edit = array(
+      'user_id' => 1,
+      'name' => $this->randomName(),
+      "{$field_name}[$langcode][0][value]" => 2,
+      'revision' => TRUE,
+    );
+    $this->drupalPost($entity_type . '/manage/' . $id . '/edit', $edit, t('Save'));
 
     // Check that the new revision has the expected values.
-    $this->container->get('plugin.manager.entity')->getStorageController('test_entity')->resetCache(array($id));
-    $entity = field_test_entity_test_load($id);
-    $this->assertEqual($entity->{$field_name_no_access}[$langcode][0]['value'], 99, 'New revision has the expected value for the field with no edit access.');
-    $this->assertEqual($entity->{$field_name}[$langcode][0]['value'], 2, 'New revision has the expected value for the field with edit access.');
+    $this->container->get('plugin.manager.entity')->getStorageController($entity_type)->resetCache(array($id));
+    $entity = entity_load($entity_type, $id);
+    $this->assertEqual($entity->$field_name_no_access->value, 99, 'New revision has the expected value for the field with no edit access.');
+    $this->assertEqual($entity->$field_name->value, 2, 'New revision has the expected value for the field with edit access.');
 
     // Check that the revision is also saved in the revisions table.
-    $entity = field_test_entity_test_load($id, $entity->ftvid);
-    $this->assertEqual($entity->{$field_name_no_access}[$langcode][0]['value'], 99, 'New revision has the expected value for the field with no edit access.');
-    $this->assertEqual($entity->{$field_name}[$langcode][0]['value'], 2, 'New revision has the expected value for the field with edit access.');
+    $entity = entity_revision_load($entity_type, $entity->getRevisionId());
+    $this->assertEqual($entity->$field_name_no_access->value, 99, 'New revision has the expected value for the field with no edit access.');
+    $this->assertEqual($entity->$field_name->value, 2, 'New revision has the expected value for the field with edit access.');
   }
 
   /**
    * Tests Field API form integration within a subform.
    */
   function testNestedFieldForm() {
-    // Add two instances on the 'test_bundle'
+    // Add two instances on the 'entity_test'
     field_create_field($this->field_single);
     field_create_field($this->field_unlimited);
     $this->instance['field_name'] = 'field_single';
diff --git a/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php b/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php
index f2ada97..cc70f06 100644
--- a/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php
@@ -37,7 +37,7 @@ function setUp() {
 
     $this->field_name = drupal_strtolower($this->randomName() . '_field_name');
 
-    $this->entity_type = 'test_entity';
+    $this->entity_type = 'entity_test';
 
     $field = array(
       'field_name' => $this->field_name,
@@ -51,10 +51,10 @@ function setUp() {
     $instance = array(
       'field_name' => $this->field_name,
       'entity_type' => $this->entity_type,
-      'bundle' => 'test_bundle',
+      'bundle' => 'entity_test',
     );
     field_create_instance($instance);
-    $this->instance = field_read_instance('test_entity', $this->field_name, 'test_bundle');
+    $this->instance = field_read_instance('entity_test', $this->field_name, 'entity_test');
 
     for ($i = 0; $i < 3; ++$i) {
       $language = new Language(array(
@@ -70,12 +70,12 @@ function setUp() {
    */
   function testFieldAvailableLanguages() {
     // Test 'translatable' fieldable info.
-    field_test_entity_info_translatable('test_entity', FALSE);
+    field_test_entity_info_translatable('entity_test', FALSE);
     $field = $this->field;
     $field['field_name'] .= '_untranslatable';
 
     // Enable field translations for the entity.
-    field_test_entity_info_translatable('test_entity', TRUE);
+    field_test_entity_info_translatable('entity_test', TRUE);
 
     // Test hook_field_languages() invocation on a translatable field.
     state()->set('field_test.field_available_languages_alter', TRUE);
@@ -101,9 +101,9 @@ function testFieldAvailableLanguages() {
    */
   function testFieldInvoke() {
     // Enable field translations for the entity.
-    field_test_entity_info_translatable('test_entity', TRUE);
+    field_test_entity_info_translatable('entity_test', TRUE);
 
-    $entity_type = 'test_entity';
+    $entity_type = 'entity_test';
     $entity = field_test_create_entity(0, 0, $this->instance['bundle']);
 
     // Populate some extra languages to check if _field_invoke() correctly uses
@@ -139,12 +139,12 @@ function testFieldInvoke() {
    */
   function testFieldInvokeMultiple() {
     // Enable field translations for the entity.
-    field_test_entity_info_translatable('test_entity', TRUE);
+    field_test_entity_info_translatable('entity_test', TRUE);
 
     $values = array();
     $options = array();
     $entities = array();
-    $entity_type = 'test_entity';
+    $entity_type = 'entity_test';
     $entity_count = 5;
     $available_langcodes = field_available_languages($this->entity_type, $this->field);
 
@@ -217,9 +217,9 @@ function testTranslatableFieldSaveLoad() {
     $this->assertTrue(count($entity_info['translation']), 'Nodes are translatable.');
 
     // Prepare the field translations.
-    field_test_entity_info_translatable('test_entity', TRUE);
+    field_test_entity_info_translatable('entity_test', TRUE);
     $eid = $evid = 1;
-    $entity_type = 'test_entity';
+    $entity_type = 'entity_test';
     $entity = field_test_create_entity($eid, $evid, $this->instance['bundle']);
     $field_translations = array();
     $available_langcodes = field_available_languages($entity_type, $this->field);
@@ -295,7 +295,7 @@ function testTranslatableFieldSaveLoad() {
    */
   function testFieldDisplayLanguage() {
     $field_name = drupal_strtolower($this->randomName() . '_field_name');
-    $entity_type = 'test_entity';
+    $entity_type = 'entity_test';
 
     // We need an additional field here to properly test display language
     // suggestions.
@@ -310,7 +310,7 @@ function testFieldDisplayLanguage() {
     $instance = array(
       'field_name' => $field['field_name'],
       'entity_type' => $entity_type,
-      'bundle' => 'test_bundle',
+      'bundle' => 'entity_test',
     );
     field_create_instance($instance);
 
@@ -387,7 +387,7 @@ function testFieldDisplayLanguage() {
    * Tests field translations when creating a new revision.
    */
   function testFieldFormTranslationRevisions() {
-    $web_user = $this->drupalCreateUser(array('access field_test content', 'administer field_test content'));
+    $web_user = $this->drupalCreateUser(array('view test entity', 'administer entity_test content'));
     $this->drupalLogin($web_user);
 
     // Prepare the field translations.
@@ -408,7 +408,7 @@ function testFieldFormTranslationRevisions() {
     // Create a new revision.
     $langcode = field_valid_language(NULL);
     $edit = array("{$field_name}[$langcode][0][value]" => $entity->{$field_name}[$langcode][0]['value'], 'revision' => TRUE);
-    $this->drupalPost('test-entity/manage/' . $eid . '/edit', $edit, t('Save'));
+    $this->drupalPost('entity_test/manage/' . $eid . '/edit', $edit, t('Save'));
 
     // Check translation revisions.
     $this->checkTranslationRevisions($eid, $eid, $available_langcodes);
diff --git a/core/modules/field/lib/Drupal/field/Tests/Views/ApiDataTest.php b/core/modules/field/lib/Drupal/field/Tests/Views/ApiDataTest.php
index 417b836..e2a3bfc 100644
--- a/core/modules/field/lib/Drupal/field/Tests/Views/ApiDataTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/Views/ApiDataTest.php
@@ -28,8 +28,6 @@ public static function getInfo() {
   function setUp() {
     parent::setUp();
 
-    $langcode = LANGUAGE_NOT_SPECIFIED;
-
     $field_names = $this->setUpFields();
 
     // The first one will be attached to nodes only.
@@ -65,9 +63,8 @@ function setUp() {
     // Now create some example nodes/users for the view result.
     for ($i = 0; $i < 5; $i++) {
       $edit = array(
-        // @TODO Write a helper method to create such values.
-        'field_name_0' => array($langcode => array((array('value' => $this->randomName())))),
-        'field_name_2' => array($langcode => array((array('value' => $this->randomName())))),
+        'field_name_0' => array((array('value' => $this->randomName()))),
+        'field_name_2' => array((array('value' => $this->randomName()))),
       );
       $this->nodes[] = $this->drupalCreateNode($edit);
     }
diff --git a/core/modules/field/lib/Drupal/field/Tests/Views/HandlerFieldFieldTest.php b/core/modules/field/lib/Drupal/field/Tests/Views/HandlerFieldFieldTest.php
index 1c8d3f5..5e50b88 100644
--- a/core/modules/field/lib/Drupal/field/Tests/Views/HandlerFieldFieldTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/Views/HandlerFieldFieldTest.php
@@ -59,13 +59,13 @@ protected function setUp() {
 
       for ($key = 0; $key < 3; $key++) {
         $field = $this->fields[$key];
-        $edit[$field['field_name']][LANGUAGE_NOT_SPECIFIED][0]['value'] = $this->randomName(8);
+        $edit[$field['field_name']][0]['value'] = $this->randomName(8);
       }
       for ($j = 0; $j < 5; $j++) {
-        $edit[$this->fields[3]['field_name']][LANGUAGE_NOT_SPECIFIED][$j]['value'] = $this->randomName(8);
+        $edit[$this->fields[3]['field_name']][$j]['value'] = $this->randomName(8);
       }
       // Set this field to be empty.
-      $edit[$this->fields[4]['field_name']] = array(LANGUAGE_NOT_SPECIFIED => array(0 => array('value' => NULL)));
+      $edit[$this->fields[4]['field_name']] = array(array('value' => NULL));
 
       $this->nodes[$i] = $this->drupalCreateNode($edit);
     }
diff --git a/core/modules/field/tests/modules/field_test/field_test.entity.inc b/core/modules/field/tests/modules/field_test/field_test.entity.inc
index 81c116d..a513ab7 100644
--- a/core/modules/field/tests/modules/field_test/field_test.entity.inc
+++ b/core/modules/field/tests/modules/field_test/field_test.entity.inc
@@ -23,45 +23,6 @@ function field_test_entity_info_alter(&$entity_info) {
 }
 
 /**
- * Implements hook_entity_view_mode_info_alter().
- */
-function field_test_entity_view_mode_info_alter(&$view_modes) {
-  $entity_info = entity_get_info();
-  foreach ($entity_info as $entity_type => $info) {
-    if ($entity_info[$entity_type]['module'] == 'field_test') {
-      $view_modes[$entity_type] = array(
-        'full' => array(
-          'label' => t('Full object'),
-          'custom_settings' => TRUE,
-        ),
-        'teaser' => array(
-          'label' => t('Teaser'),
-          'custom_settings' => TRUE,
-        ),
-      );
-    }
-  }
-}
-
-/**
- * Implements hook_entity_bundle_info_alter().
- */
-function field_test_entity_bundle_info_alter(&$bundles) {
-  $entity_info = entity_get_info();
-  foreach ($bundles as $entity_type => $info) {
-    if ($entity_info[$entity_type]['module'] == 'field_test') {
-      $bundles[$entity_type] = state()->get('field_test_bundles') ?: array('test_bundle' => array('label' => 'Test Bundle'));
-      if ($entity_type == 'test_entity_bundle') {
-        $bundles[$entity_type] += array('test_entity_2' => array('label' => 'Test entity 2'));
-      }
-      if ($entity_type == 'test_entity_bundle_key') {
-        $bundles[$entity_type] += array('bundle1' => array('label' => 'Bundle1'), 'bundle2' => array('label' => 'Bundle2'));
-      }
-    }
-  }
-}
-
-/**
  * Helper function to enable entity translations.
  */
 function field_test_entity_info_translatable($entity_type = NULL, $translatable = NULL) {
@@ -75,28 +36,6 @@ function field_test_entity_info_translatable($entity_type = NULL, $translatable
 }
 
 /**
- * Creates a new bundle for test_entity entities.
- *
- * @param $bundle
- *   The machine-readable name of the bundle.
- * @param $text
- *   The human-readable name of the bundle. If none is provided, the machine
- *   name will be used.
- */
-function field_test_create_bundle($bundle, $text = NULL) {
-  $bundles = state()->get('field_test.bundles') ?: array('test_bundle' => array('label' => 'Test Bundle'));
-  $bundles += array($bundle => array('label' => $text ? $text : $bundle));
-  state()->set('field_test.bundles', $bundles);
-
-  $info = entity_get_info();
-  foreach ($info as $type => $type_info) {
-    if ($type_info['module'] == 'field_test') {
-      field_attach_create_bundle($type, $bundle);
-    }
-  }
-}
-
-/**
  * Renames a bundle for test_entity entities.
  *
  * @param $bundle_old
@@ -252,11 +191,11 @@ function field_test_entity_nested_form($form, &$form_state, $entity_1, $entity_2
  * Validate handler for field_test_entity_nested_form().
  */
 function field_test_entity_nested_form_validate($form, &$form_state) {
-  $entity_1 = entity_create('test_entity', $form_state['values']);
+  $entity_1 = entity_create('entity_test', $form_state['values']);
   field_attach_extract_form_values($entity_1, $form, $form_state);
   field_attach_form_validate($entity_1, $form, $form_state);
 
-  $entity_2 = entity_create('test_entity', $form_state['values']['entity_2']);
+  $entity_2 = entity_create('entity_test', $form_state['values']['entity_2']);
   field_attach_extract_form_values($entity_2, $form['entity_2'], $form_state);
   field_attach_form_validate($entity_2, $form['entity_2'], $form_state);
 }
@@ -265,11 +204,11 @@ function field_test_entity_nested_form_validate($form, &$form_state) {
  * Submit handler for field_test_entity_nested_form().
  */
 function field_test_entity_nested_form_submit($form, &$form_state) {
-  $entity_1 = entity_create('test_entity', $form_state['values']);
+  $entity_1 = entity_create('entity_test', $form_state['values']);
   field_attach_extract_form_values($entity_1, $form, $form_state);
   field_test_entity_save($entity_1);
 
-  $entity_2 = entity_create('test_entity', $form_state['values']['entity_2']);
+  $entity_2 = entity_create('entity_test', $form_state['values']['entity_2']);
   field_attach_extract_form_values($entity_2, $form['entity_2'], $form_state);
   field_test_entity_save($entity_2);
 
diff --git a/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Core/Entity/TestEntity.php b/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Core/Entity/TestEntity.php
index 8a5a465..a5911e9 100644
--- a/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Core/Entity/TestEntity.php
+++ b/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Core/Entity/TestEntity.php
@@ -19,7 +19,6 @@
  *   label = @Translation("Test Entity"),
  *   module = "field_test",
  *   controller_class = "Drupal\field_test\TestEntityController",
- *   render_controller_class = "Drupal\Core\Entity\EntityRenderController",
  *   form_controller_class = {
  *     "default" = "Drupal\field_test\TestEntityFormController"
  *   },
diff --git a/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/TestEntityFormController.php b/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/TestEntityFormController.php
index 93ef2aa..5c4bdf7 100644
--- a/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/TestEntityFormController.php
+++ b/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/TestEntityFormController.php
@@ -40,11 +40,11 @@ public function save(array $form, array &$form_state) {
     $is_new = $entity->isNew();
     $entity->save();
 
-    $message = $is_new ? t('test_entity @id has been created.', array('@id' => $entity->id())) : t('test_entity @id has been updated.', array('@id' => $entity->id()));
+    $message = $is_new ? t('entity_test @id has been created.', array('@id' => $entity->id())) : t('test_entity @id has been updated.', array('@id' => $entity->id()));
     drupal_set_message($message);
 
     if ($entity->id()) {
-      $form_state['redirect'] = 'test-entity/manage/' . $entity->id() . '/edit';
+      $form_state['redirect'] = 'entity_test/manage/' . $entity->id() . '/edit';
     }
     else {
       // Error on save.
diff --git a/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Type/TestItem.php b/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Type/TestItem.php
index 0c61d15..bc3b9fd 100644
--- a/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Type/TestItem.php
+++ b/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Type/TestItem.php
@@ -33,6 +33,10 @@ public function getPropertyDefinitions() {
         'type' => 'integer',
         'label' => t('Test integer value'),
       );
+      static::$propertyDefinitions['additional_key'] = array(
+        'type' => 'string',
+        'label' => t('Additional test value'),
+      );
     }
     return static::$propertyDefinitions;
   }
diff --git a/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Tests/FieldSqlStorageTest.php b/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Tests/FieldSqlStorageTest.php
index e79757e..27b0df8 100644
--- a/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Tests/FieldSqlStorageTest.php
+++ b/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Tests/FieldSqlStorageTest.php
@@ -25,7 +25,7 @@ class FieldSqlStorageTest extends WebTestBase {
    *
    * @var array
    */
-  public static $modules = array('field_sql_storage', 'field', 'field_test', 'text', 'number');
+  public static $modules = array('field_sql_storage', 'field', 'field_test', 'text', 'number', 'entity_test');
 
   public static function getInfo() {
     return array(
@@ -37,14 +37,15 @@ public static function getInfo() {
 
   function setUp() {
     parent::setUp();
+    $entity_type = 'entity_test_rev';
 
     $this->field_name = strtolower($this->randomName());
     $this->field = array('field_name' => $this->field_name, 'type' => 'test_field', 'cardinality' => 4);
     $this->field = field_create_field($this->field);
     $this->instance = array(
       'field_name' => $this->field_name,
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle'
+      'entity_type' => $entity_type,
+      'bundle' => $entity_type
     );
     $this->instance = field_create_instance($this->instance);
     $this->table = _field_sql_storage_tablename($this->field);
@@ -57,7 +58,7 @@ function setUp() {
    * field_load_revision works correctly.
    */
   function testFieldAttachLoad() {
-    $entity_type = 'test_entity';
+    $entity_type = 'entity_test_rev';
     $eid = 0;
     $langcode = LANGUAGE_NOT_SPECIFIED;
 
@@ -84,27 +85,33 @@ function testFieldAttachLoad() {
     $query->execute();
 
     // Load the "most current revision"
-    $entity = field_test_create_entity($eid, 0, $this->instance['bundle']);
-    field_attach_load($entity_type, array($eid => $entity));
+    $entity = entity_create($entity_type, array(
+      'id' => 0,
+      'revision_id' => 0,
+    ));
+    field_attach_load($entity_type, array($eid => $entity->getBCEntity()));
     foreach ($values[0] as $delta => $value) {
       if ($delta < $this->field['cardinality']) {
-        $this->assertEqual($entity->{$this->field_name}[$langcode][$delta]['value'], $value, "Value $delta is loaded correctly for current revision");
+        $this->assertEqual($entity->{$this->field_name}[$delta]->value, $value, "Value $delta is loaded correctly for current revision");
       }
       else {
-        $this->assertFalse(array_key_exists($delta, $entity->{$this->field_name}[$langcode]), "No extraneous value gets loaded for current revision.");
+        $this->assertFalse(array_key_exists($delta, $entity->{$this->field_name}), "No extraneous value gets loaded for current revision.");
       }
     }
 
     // Load every revision
     for ($evid = 0; $evid < 4; ++$evid) {
-      $entity = field_test_create_entity($eid, $evid, $this->instance['bundle']);
-      field_attach_load_revision($entity_type, array($eid => $entity));
+      $entity = entity_create($entity_type, array(
+        'id' => $eid,
+        'revision_id' => $evid,
+      ));
+      field_attach_load_revision($entity_type, array($eid => $entity->getBCEntity()));
       foreach ($values[$evid] as $delta => $value) {
         if ($delta < $this->field['cardinality']) {
-          $this->assertEqual($entity->{$this->field_name}[$langcode][$delta]['value'], $value, "Value $delta for revision $evid is loaded correctly");
+          $this->assertEqual($entity->{$this->field_name}[$delta]->value, $value, "Value $delta for revision $evid is loaded correctly");
         }
         else {
-          $this->assertFalse(array_key_exists($delta, $entity->{$this->field_name}[$langcode]), "No extraneous value gets loaded for revision $evid.");
+          $this->assertFalse(array_key_exists($delta, $entity->{$this->field_name}), "No extraneous value gets loaded for revision $evid.");
         }
       }
     }
@@ -113,11 +120,14 @@ function testFieldAttachLoad() {
     // loaded.
     $eid = $evid = 1;
     $unavailable_langcode = 'xx';
-    $entity = field_test_create_entity($eid, $evid, $this->instance['bundle']);
+    $entity = entity_create($entity_type, array(
+      'id' => $eid,
+      'revision_id' => $evid,
+    ));
     $values = array($entity_type, $eid, $evid, 0, $unavailable_langcode, mt_rand(1, 127));
     db_insert($this->table)->fields($columns)->values($values)->execute();
     db_insert($this->revision_table)->fields($columns)->values($values)->execute();
-    field_attach_load($entity_type, array($eid => $entity));
+    field_attach_load($entity_type, array($eid => $entity->getBCEntity()));
     $this->assertFalse(array_key_exists($unavailable_langcode, $entity->{$this->field_name}), 'Field translation in an unavailable language ignored');
   }
 
@@ -126,8 +136,11 @@ function testFieldAttachLoad() {
    * written when using insert and update.
    */
   function testFieldAttachInsertAndUpdate() {
-    $entity_type = 'test_entity';
-    $entity = field_test_create_entity(0, 0, $this->instance['bundle']);
+    $entity_type = 'entity_test_rev';
+    $entity = entity_create($entity_type, array(
+      'id' => 0,
+      'revision_id' => 0,
+    ));
     $langcode = LANGUAGE_NOT_SPECIFIED;
 
     // Test insert.
@@ -137,8 +150,8 @@ function testFieldAttachInsertAndUpdate() {
     for ($delta = 0; $delta <= $this->field['cardinality']; $delta++) {
       $values[$delta]['value'] = mt_rand(1, 127);
     }
-    $entity->{$this->field_name}[$langcode] = $rev_values[0] = $values;
-    field_attach_insert($entity);
+    $entity->{$this->field_name} = $rev_values[0] = $values;
+    field_attach_insert($entity->getBCEntity());
 
     $rows = db_select($this->table, 't')->fields('t')->execute()->fetchAllAssoc('delta', PDO::FETCH_ASSOC);
     foreach ($values as $delta => $value) {
@@ -151,14 +164,18 @@ function testFieldAttachInsertAndUpdate() {
     }
 
     // Test update.
-    $entity = field_test_create_entity(0, 1, $this->instance['bundle']);
+    $entity = entity_create($entity_type, array(
+      'id' => 0,
+      'revision_id' => 1,
+    ));
     $values = array();
     // Note: we try to update one extra value ('<=' instead of '<').
     for ($delta = 0; $delta <= $this->field['cardinality']; $delta++) {
       $values[$delta]['value'] = mt_rand(1, 127);
     }
-    $entity->{$this->field_name}[$langcode] = $rev_values[1] = $values;
-    field_attach_update($entity);
+    $rev_values[1] = $values;
+    $entity->{$this->field_name}->setValue($values);
+    field_attach_update($entity->getBCEntity());
     $rows = db_select($this->table, 't')->fields('t')->execute()->fetchAllAssoc('delta', PDO::FETCH_ASSOC);
     foreach ($values as $delta => $value) {
       if ($delta < $this->field['cardinality']) {
@@ -188,7 +205,7 @@ function testFieldAttachInsertAndUpdate() {
     // Check that update leaves the field data untouched if
     // $entity->{$field_name} is absent.
     unset($entity->{$this->field_name});
-    field_attach_update($entity);
+    field_attach_update($entity->getBCEntity());
     $rows = db_select($this->table, 't')->fields('t')->execute()->fetchAllAssoc('delta', PDO::FETCH_ASSOC);
     foreach ($values as $delta => $value) {
       if ($delta < $this->field['cardinality']) {
@@ -198,7 +215,7 @@ function testFieldAttachInsertAndUpdate() {
 
     // Check that update with an empty $entity->$field_name empties the field.
     $entity->{$this->field_name} = NULL;
-    field_attach_update($entity);
+    field_attach_update($entity->getBCEntity());
     $rows = db_select($this->table, 't')->fields('t')->execute()->fetchAllAssoc('delta', PDO::FETCH_ASSOC);
     $this->assertEqual(count($rows), 0, t("Update with an empty field_name entry empties the field."));
   }
@@ -207,12 +224,15 @@ function testFieldAttachInsertAndUpdate() {
    * Tests insert and update with missing or NULL fields.
    */
   function testFieldAttachSaveMissingData() {
-    $entity_type = 'test_entity';
-    $entity = field_test_create_entity(0, 0, $this->instance['bundle']);
+    $entity_type = 'entity_test_rev';
+    $entity = entity_create($entity_type, array(
+      'id' => 0,
+      'revision_id' => 0,
+    ));
     $langcode = LANGUAGE_NOT_SPECIFIED;
 
     // Insert: Field is missing
-    field_attach_insert($entity);
+    field_attach_insert($entity->getBCEntity());
     $count = db_select($this->table)
       ->countQuery()
       ->execute()
@@ -221,7 +241,7 @@ function testFieldAttachSaveMissingData() {
 
     // Insert: Field is NULL
     $entity->{$this->field_name} = NULL;
-    field_attach_insert($entity);
+    field_attach_insert($entity->getBCEntity());
     $count = db_select($this->table)
       ->countQuery()
       ->execute()
@@ -229,8 +249,8 @@ function testFieldAttachSaveMissingData() {
     $this->assertEqual($count, 0, 'NULL field results in no inserts');
 
     // Add some real data
-    $entity->{$this->field_name}[$langcode] = array(0 => array('value' => 1));
-    field_attach_insert($entity);
+    $entity->{$this->field_name}->value = 1;
+    field_attach_insert($entity->getBCEntity());
     $count = db_select($this->table)
       ->countQuery()
       ->execute()
@@ -239,7 +259,7 @@ function testFieldAttachSaveMissingData() {
 
     // Update: Field is missing. Data should survive.
     unset($entity->{$this->field_name});
-    field_attach_update($entity);
+    field_attach_update($entity->getBCEntity());
     $count = db_select($this->table)
       ->countQuery()
       ->execute()
@@ -248,7 +268,7 @@ function testFieldAttachSaveMissingData() {
 
     // Update: Field is NULL. Data should be wiped.
     $entity->{$this->field_name} = NULL;
-    field_attach_update($entity);
+    field_attach_update($entity->getBCEntity());
     $count = db_select($this->table)
       ->countQuery()
       ->execute()
@@ -268,8 +288,8 @@ function testFieldAttachSaveMissingData() {
     $this->assertEqual($count, 1, 'Field translation in an unavailable language saved.');
 
     // Again add some real data.
-    $entity->{$this->field_name}[$langcode] = array(0 => array('value' => 1));
-    field_attach_insert($entity);
+    $entity->{$this->field_name}->value = 1;
+    field_attach_insert($entity->getBCEntity());
     $count = db_select($this->table)
       ->countQuery()
       ->execute()
@@ -278,9 +298,9 @@ function testFieldAttachSaveMissingData() {
 
     // Update: Field translation is missing but field is not empty. Translation
     // data should survive.
-    $entity->{$this->field_name}[$unavailable_langcode] = array(mt_rand(1, 127));
+    $entity->set($this->field_name, $unavailable_langcode, array(mt_rand(1, 127)));
     unset($entity->{$this->field_name}[$langcode]);
-    field_attach_update($entity);
+    field_attach_update($entity->getBCEntity());
     $count = db_select($this->table)
       ->countQuery()
       ->execute()
@@ -290,7 +310,7 @@ function testFieldAttachSaveMissingData() {
     // Update: Field translation is NULL but field is not empty. Translation
     // data should be wiped.
     $entity->{$this->field_name}[$langcode] = NULL;
-    field_attach_update($entity);
+    field_attach_update($entity->getBCEntity());
     $count = db_select($this->table)
       ->countQuery()
       ->execute()
@@ -302,13 +322,17 @@ function testFieldAttachSaveMissingData() {
    * Test trying to update a field with data.
    */
   function testUpdateFieldSchemaWithData() {
+    $entity_type = 'entity_test_rev';
     // Create a decimal 5.2 field and add some data.
     $field = array('field_name' => 'decimal52', 'type' => 'number_decimal', 'settings' => array('precision' => 5, 'scale' => 2));
     $field = field_create_field($field);
-    $instance = array('field_name' => 'decimal52', 'entity_type' => 'test_entity', 'bundle' => 'test_bundle');
+    $instance = array('field_name' => 'decimal52', 'entity_type' => $entity_type, 'bundle' => $entity_type);
     $instance = field_create_instance($instance);
-    $entity = field_test_create_entity(0, 0, $instance['bundle']);
-    $entity->decimal52[LANGUAGE_NOT_SPECIFIED][0]['value'] = '1.235';
+    $entity = entity_create($entity_type, array(
+      'id' => 0,
+      'revision_id' => 0,
+    ));
+    $entity->decimal52->value = '1.235';
     $entity->save();
 
     // Attempt to update the field in a way that would work without data.
@@ -351,12 +375,13 @@ function testFieldUpdateFailure() {
    * Test adding and removing indexes while data is present.
    */
   function testFieldUpdateIndexesWithData() {
+    $entity_type = 'entity_test_rev';
 
     // Create a decimal field.
     $field_name = 'testfield';
     $field = array('field_name' => $field_name, 'type' => 'text');
     $field = field_create_field($field);
-    $instance = array('field_name' => $field_name, 'entity_type' => 'test_entity', 'bundle' => 'test_bundle');
+    $instance = array('field_name' => $field_name, 'entity_type' => $entity_type, 'bundle' => $entity_type);
     $instance = field_create_instance($instance);
     $tables = array(_field_sql_storage_tablename($field), _field_sql_storage_revision_tablename($field));
 
@@ -367,8 +392,12 @@ function testFieldUpdateIndexesWithData() {
     }
 
     // Add data so the table cannot be dropped.
-    $entity = field_test_create_entity(1, 1, $instance['bundle']);
-    $entity->{$field_name}[LANGUAGE_NOT_SPECIFIED][0]['value'] = 'field data';
+    $entity = entity_create($entity_type, array(
+      'id' => 1,
+      'revision_id' => 1,
+    ));
+    $entity->$field_name->value = 'field data';
+    $entity->enforceIsNew();
     $entity->save();
 
     // Add an index
@@ -387,9 +416,12 @@ function testFieldUpdateIndexesWithData() {
     }
 
     // Verify that the tables were not dropped.
-    $entity = field_test_create_entity(1, 1, $instance['bundle']);
-    field_attach_load('test_entity', array(1 => $entity));
-    $this->assertEqual($entity->{$field_name}[LANGUAGE_NOT_SPECIFIED][0]['value'], 'field data', t("Index changes performed without dropping the tables"));
+    $entity = entity_create($entity_type, array(
+      'id' => 1,
+      'revision_id' => 1,
+    ));
+    field_attach_load($entity_type, array(1 => $entity->getBCEntity()));
+    $this->assertEqual($entity->$field_name->value, 'field data', t("Index changes performed without dropping the tables"));
   }
 
   /**
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageDisplayTest.php b/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageDisplayTest.php
index 45de66e..4ca882b 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageDisplayTest.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageDisplayTest.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\field_ui\Tests;
 
-use Drupal\node\Plugin\Core\Entity\Node;
+use Drupal\Core\Entity\EntityInterface;
 
 /**
  * Tests the functionality of the 'Manage display' screens.
@@ -111,7 +111,7 @@ function testViewModeCustom() {
     $value = 12345;
     $settings = array(
       'type' => $this->type,
-      'field_test' => array(LANGUAGE_NOT_SPECIFIED => array(array('value' => $value))),
+      'field_test' => array(array('value' => $value)),
     );
     $node = $this->drupalCreateNode($settings);
 
@@ -216,7 +216,7 @@ function testNoFieldsDisplayOverview() {
   /**
    * Asserts that a string is found in the rendered node in a view mode.
    *
-   * @param Node $node
+   * @param EntityInterface $node
    *   The node.
    * @param $view_mode
    *   The view mode in which the node should be displayed.
@@ -228,14 +228,14 @@ function testNoFieldsDisplayOverview() {
    * @return
    *   TRUE on pass, FALSE on fail.
    */
-  function assertNodeViewText(Node $node, $view_mode, $text, $message) {
+  function assertNodeViewText(EntityInterface $node, $view_mode, $text, $message) {
     return $this->assertNodeViewTextHelper($node, $view_mode, $text, $message, FALSE);
   }
 
   /**
    * Asserts that a string is not found in the rendered node in a view mode.
    *
-   * @param Node $node
+   * @param EntityInterface $node
    *   The node.
    * @param $view_mode
    *   The view mode in which the node should be displayed.
@@ -246,7 +246,7 @@ function assertNodeViewText(Node $node, $view_mode, $text, $message) {
    * @return
    *   TRUE on pass, FALSE on fail.
    */
-  function assertNodeViewNoText(Node $node, $view_mode, $text, $message) {
+  function assertNodeViewNoText(EntityInterface $node, $view_mode, $text, $message) {
     return $this->assertNodeViewTextHelper($node, $view_mode, $text, $message, TRUE);
   }
 
@@ -256,7 +256,7 @@ function assertNodeViewNoText(Node $node, $view_mode, $text, $message) {
    * This helper function is used by assertNodeViewText() and
    * assertNodeViewNoText().
    *
-   * @param Node $node
+   * @param EntityInterface $node
    *   The node.
    * @param $view_mode
    *   The view mode in which the node should be displayed.
@@ -270,7 +270,7 @@ function assertNodeViewNoText(Node $node, $view_mode, $text, $message) {
    * @return
    *   TRUE on pass, FALSE on fail.
    */
-  function assertNodeViewTextHelper(Node $node, $view_mode, $text, $message, $not_exists) {
+  function assertNodeViewTextHelper(EntityInterface $node, $view_mode, $text, $message, $not_exists) {
     // Make sure caches on the tester side are refreshed after changes
     // submitted on the tested side.
     field_info_cache_clear();
diff --git a/core/modules/file/lib/Drupal/file/Tests/FileFieldTestBase.php b/core/modules/file/lib/Drupal/file/Tests/FileFieldTestBase.php
index 52df6f2..c2d922d 100644
--- a/core/modules/file/lib/Drupal/file/Tests/FileFieldTestBase.php
+++ b/core/modules/file/lib/Drupal/file/Tests/FileFieldTestBase.php
@@ -141,7 +141,8 @@ function uploadNodeFile($file, $field_name, $nid_or_type, $new_revision = TRUE,
       $node = $this->drupalCreateNode($extras);
       $nid = $node->nid;
       // Save at least one revision to better simulate a real site.
-      $this->drupalCreateNode(get_object_vars($node));
+      $node->setNewRevision();
+      $node->save();
       $node = node_load($nid, TRUE);
       $this->assertNotEqual($nid, $node->vid, t('Node revision exists.'));
     }
diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module
index 8b35c3e..574d536 100644
--- a/core/modules/forum/forum.module
+++ b/core/modules/forum/forum.module
@@ -6,7 +6,6 @@
  */
 
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\node\Plugin\Core\Entity\Node;
 use Drupal\entity\Plugin\Core\Entity\EntityDisplay;
 use Drupal\taxonomy\Plugin\Core\Entity\Term;
 
@@ -241,13 +240,13 @@ function forum_uri($forum) {
 /**
  * Checks whether a node can be used in a forum, based on its content type.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   A node entity.
  *
  * @return
  *   Boolean indicating if the node can be assigned to a forum.
  */
-function _forum_node_check_node_type(Node $node) {
+function _forum_node_check_node_type(EntityInterface $node) {
   // Fetch information about the forum field.
   $instance = field_info_instance('node', 'taxonomy_forums', $node->type);
   return !empty($instance);
@@ -256,7 +255,7 @@ function _forum_node_check_node_type(Node $node) {
 /**
  * Implements hook_node_view().
  */
-function forum_node_view(Node $node, EntityDisplay $display, $view_mode) {
+function forum_node_view(EntityInterface $node, EntityDisplay $display, $view_mode) {
   $vid = config('forum.settings')->get('vocabulary');
   $vocabulary = taxonomy_vocabulary_load($vid);
   if (_forum_node_check_node_type($node)) {
@@ -282,7 +281,7 @@ function forum_node_view(Node $node, EntityDisplay $display, $view_mode) {
  * Checks in particular that the node is assigned only a "leaf" term in the
  * forum taxonomy.
  */
-function forum_node_validate(Node $node, $form) {
+function forum_node_validate(EntityInterface $node, $form) {
   if (_forum_node_check_node_type($node)) {
     $langcode = $form['taxonomy_forums']['#language'];
     // vocabulary is selected, not a "container" term.
@@ -318,7 +317,7 @@ function forum_node_validate(Node $node, $form) {
  *
  * Assigns the forum taxonomy when adding a topic from within a forum.
  */
-function forum_node_presave(Node $node) {
+function forum_node_presave(EntityInterface $node) {
   if (_forum_node_check_node_type($node)) {
     // Make sure all fields are set properly:
     $node->icon = !empty($node->icon) ? $node->icon : '';
@@ -338,7 +337,7 @@ function forum_node_presave(Node $node) {
 /**
  * Implements hook_node_update().
  */
-function forum_node_update(Node $node) {
+function forum_node_update(EntityInterface $node) {
   if (_forum_node_check_node_type($node)) {
     // If this is not a new revision and does exist, update the forum record,
     // otherwise insert a new one.
@@ -388,7 +387,7 @@ function forum_node_update(Node $node) {
 /**
  * Implements hook_node_insert().
  */
-function forum_node_insert(Node $node) {
+function forum_node_insert(EntityInterface $node) {
   if (_forum_node_check_node_type($node)) {
     if (!empty($node->forum_tid)) {
       $nid = db_insert('forum')
@@ -405,7 +404,7 @@ function forum_node_insert(Node $node) {
 /**
  * Implements hook_node_predelete().
  */
-function forum_node_predelete(Node $node) {
+function forum_node_predelete(EntityInterface $node) {
   if (_forum_node_check_node_type($node)) {
     db_delete('forum')
       ->condition('nid', $node->nid)
@@ -522,18 +521,17 @@ function forum_comment_delete($comment) {
 function forum_field_storage_pre_insert(EntityInterface $entity, &$skip_fields) {
   if ($entity->entityType() == 'node' && $entity->status && _forum_node_check_node_type($entity)) {
     $query = db_insert('forum_index')->fields(array('nid', 'title', 'tid', 'sticky', 'created', 'comment_count', 'last_comment_timestamp'));
-    foreach ($entity->taxonomy_forums as $language) {
-      foreach ($language as $item) {
-        $query->values(array(
-          'nid' => $entity->nid,
-          'title' => $entity->title,
-          'tid' => $item['tid'],
-          'sticky' => $entity->sticky,
-          'created' => $entity->created,
-          'comment_count' => 0,
-          'last_comment_timestamp' => $entity->created,
-        ));
-      }
+    foreach ($entity->getTranslationLanguages() as $langcode => $language) {
+      $translation = $entity->getTranslation($langcode, FALSE);
+      $query->values(array(
+        'nid' => $entity->id(),
+        'title' => $translation->title->value,
+        'tid' => $translation->taxonomy_forums->tid,
+        'sticky' => $entity->sticky,
+        'created' => $entity->created,
+        'comment_count' => 0,
+        'last_comment_timestamp' => $entity->created,
+      ));
     }
     $query->execute();
   }
@@ -656,7 +654,7 @@ function forum_block_view_pre_render($elements) {
 /**
  * Implements hook_form().
  */
-function forum_form(Node $node, &$form_state) {
+function forum_form(EntityInterface $node, &$form_state) {
   $type = node_type_load($node->type);
   $form['title'] = array(
     '#type' => 'textfield',
diff --git a/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php b/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php
index 5070396..c08ce70 100644
--- a/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php
+++ b/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\forum\Tests;
 
-use Drupal\node\Plugin\Core\Entity\Node;
+use Drupal\Core\Entity\EntityInterface;
 use Drupal\simpletest\WebTestBase;
 
 /**
@@ -540,14 +540,14 @@ function createForumTopic($forum, $container = FALSE) {
    *
    * @param $node_user
    *   The user who creates the node.
-   * @param Drupal\node\Node $node
+   * @param \Drupal\Core\Entity\EntityInterface $node
    *   The node being checked.
    * @param $admin
    *   Boolean to indicate whether the user can 'access administration pages'.
    * @param $response
    *   The exptected HTTP response code.
    */
-  private function verifyForums($node_user, Node $node, $admin, $response = 200) {
+  private function verifyForums($node_user, EntityInterface $node, $admin, $response = 200) {
     $response2 = ($admin) ? 200 : 403;
 
     // View forum help node.
diff --git a/core/modules/history/history.module b/core/modules/history/history.module
index 45027fe..84abade 100644
--- a/core/modules/history/history.module
+++ b/core/modules/history/history.module
@@ -9,7 +9,7 @@
  * - Generic helper for node_mark().
  */
 
-use Drupal\node\Plugin\Core\Entity\Node;
+use Drupal\Core\Entity\EntityInterface;
 
 /**
  * Entities changed before this time are always shown as read.
@@ -79,7 +79,7 @@ function history_cron() {
 /**
  * Implements hook_node_delete().
  */
-function history_node_delete(Node $node) {
+function history_node_delete(EntityInterface $node) {
   db_delete('history')
     ->condition('nid', $node->nid)
     ->execute();
diff --git a/core/modules/link/lib/Drupal/link/Tests/LinkFieldTest.php b/core/modules/link/lib/Drupal/link/Tests/LinkFieldTest.php
index a608873..f83e2c6 100644
--- a/core/modules/link/lib/Drupal/link/Tests/LinkFieldTest.php
+++ b/core/modules/link/lib/Drupal/link/Tests/LinkFieldTest.php
@@ -19,7 +19,7 @@ class LinkFieldTest extends WebTestBase {
    *
    * @var array
    */
-  public static $modules = array('field_test', 'link');
+  public static $modules = array('entity_test', 'link');
 
   public static function getInfo() {
     return array(
@@ -33,8 +33,8 @@ function setUp() {
     parent::setUp();
 
     $this->web_user = $this->drupalCreateUser(array(
-      'access field_test content',
-      'administer field_test content',
+      'view test entity',
+      'administer entity_test content',
     ));
     $this->drupalLogin($this->web_user);
   }
@@ -51,8 +51,8 @@ function testURLValidation() {
     field_create_field($this->field);
     $this->instance = array(
       'field_name' => $this->field['field_name'],
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle',
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
       'settings' => array(
         'title' => DRUPAL_DISABLED,
       ),
@@ -64,7 +64,7 @@ function testURLValidation() {
       ),
     );
     field_create_instance($this->instance);
-    entity_get_display('test_entity', 'test_bundle', 'full')
+    entity_get_display('entity_test', 'entity_test', 'full')
       ->setComponent($this->field['field_name'], array(
         'type' => 'link',
       ))
@@ -73,19 +73,21 @@ function testURLValidation() {
     $langcode = LANGUAGE_NOT_SPECIFIED;
 
     // Display creation form.
-    $this->drupalGet('test-entity/add/test_bundle');
+    $this->drupalGet('entity_test/add');
     $this->assertFieldByName("{$this->field['field_name']}[$langcode][0][url]", '', 'Link URL field is displayed');
     $this->assertRaw('placeholder="http://example.com"');
 
     // Verify that a valid URL can be submitted.
     $value = 'http://www.example.com/';
     $edit = array(
+      'user_id' => 1,
+      'name' => $this->randomName(),
       "{$this->field['field_name']}[$langcode][0][url]" => $value,
     );
     $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
+    preg_match('|entity_test/manage/(\d+)/edit|', $this->url, $match);
     $id = $match[1];
-    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)));
+    $this->assertText(t('entity_test @id has been created.', array('@id' => $id)));
     $this->assertRaw($value);
 
     // Verify that invalid URLs cannot be submitted.
@@ -97,9 +99,11 @@ function testURLValidation() {
       // Missing host name
       'http://',
     );
-    $this->drupalGet('test-entity/add/test_bundle');
+    $this->drupalGet('entity_test/add');
     foreach ($wrong_entries as $invalid_value) {
       $edit = array(
+        'user_id' => 1,
+        'name' => $this->randomName(),
         "{$this->field['field_name']}[$langcode][0][url]" => $invalid_value,
       );
       $this->drupalPost(NULL, $edit, t('Save'));
@@ -119,8 +123,8 @@ function testLinkTitle() {
     field_create_field($this->field);
     $this->instance = array(
       'field_name' => $this->field['field_name'],
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle',
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
       'settings' => array(
         'title' => DRUPAL_OPTIONAL,
       ),
@@ -133,7 +137,7 @@ function testLinkTitle() {
       ),
     );
     field_create_instance($this->instance);
-    entity_get_display('test_entity', 'test_bundle', 'full')
+    entity_get_display('entity_test', 'entity_test', 'full')
       ->setComponent($this->field['field_name'], array(
         'type' => 'link',
         'label' => 'hidden',
@@ -149,7 +153,7 @@ function testLinkTitle() {
       field_update_instance($this->instance);
 
       // Display creation form.
-      $this->drupalGet('test-entity/add/test_bundle');
+      $this->drupalGet('entity_test/add');
       $this->assertFieldByName("{$this->field['field_name']}[$langcode][0][url]", '', 'URL field found.');
       $this->assertRaw('placeholder="http://example.com"');
 
@@ -177,7 +181,7 @@ function testLinkTitle() {
           $this->assertNoText(t('!name field is required.', array('!name' => t('Title'))));
 
           // Verify that a URL and title meets requirements.
-          $this->drupalGet('test-entity/add/test_bundle');
+          $this->drupalGet('entity_test/add');
           $edit = array(
             "{$this->field['field_name']}[$langcode][0][url]" => 'http://www.example.com',
             "{$this->field['field_name']}[$langcode][0][title]" => 'Example',
@@ -191,13 +195,15 @@ function testLinkTitle() {
     // Verify that a link without title is rendered using the URL as link text.
     $value = 'http://www.example.com/';
     $edit = array(
+      'user_id' => 1,
+      'name' => $this->randomName(),
       "{$this->field['field_name']}[$langcode][0][url]" => $value,
       "{$this->field['field_name']}[$langcode][0][title]" => '',
     );
     $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
+    preg_match('|entity_test/manage/(\d+)/edit|', $this->url, $match);
     $id = $match[1];
-    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)));
+    $this->assertText(t('entity_test @id has been created.', array('@id' => $id)));
 
     $this->renderTestEntity($id);
     $expected_link = l($value, $value);
@@ -206,10 +212,12 @@ function testLinkTitle() {
     // Verify that a link with title is rendered using the title as link text.
     $title = $this->randomName();
     $edit = array(
+      'user_id' => 1,
+      'name' => $this->randomName(),
       "{$this->field['field_name']}[$langcode][0][title]" => $title,
     );
-    $this->drupalPost("test-entity/manage/$id/edit", $edit, t('Save'));
-    $this->assertRaw(t('test_entity @id has been updated.', array('@id' => $id)));
+    $this->drupalPost("entity_test/manage/$id/edit", $edit, t('Save'));
+    $this->assertText(t('entity_test @id has been updated.', array('@id' => $id)));
 
     $this->renderTestEntity($id);
     $expected_link = l($title, $value);
@@ -229,8 +237,8 @@ function testLinkFormatter() {
     field_create_field($this->field);
     $this->instance = array(
       'field_name' => $this->field['field_name'],
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle',
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
       'settings' => array(
         'title' => DRUPAL_OPTIONAL,
       ),
@@ -243,7 +251,7 @@ function testLinkFormatter() {
       'label' => 'hidden',
     );
     field_create_instance($this->instance);
-    entity_get_display('test_entity', 'test_bundle', 'full')
+    entity_get_display('entity_test', 'entity_test', 'full')
       ->setComponent($this->field['field_name'], $display_options)
       ->save();
 
@@ -254,13 +262,15 @@ function testLinkFormatter() {
     // - The second field item uses a URL and title.
     // For consistency in assertion code below, the URL is assigned to the title
     // variable for the first field.
-    $this->drupalGet('test-entity/add/test_bundle');
+    $this->drupalGet('entity_test/add');
     $url1 = 'http://www.example.com/content/articles/archive?author=John&year=2012#com';
     $url2 = 'http://www.example.org/content/articles/archive?author=John&year=2012#org';
     $title1 = $url1;
     // Intentionally contains an ampersand that needs sanitization on output.
     $title2 = 'A very long & strange example title that could break the nice layout of the site';
     $edit = array(
+      'user_id' => 1,
+      'name' => $this->randomName(),
       "{$this->field['field_name']}[$langcode][0][url]" => $url1,
       // Note that $title1 is not submitted.
       "{$this->field['field_name']}[$langcode][0][title]" => '',
@@ -268,9 +278,9 @@ function testLinkFormatter() {
       "{$this->field['field_name']}[$langcode][1][title]" => $title2,
     );
     $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
+    preg_match('|entity_test/manage/(\d+)/edit|', $this->url, $match);
     $id = $match[1];
-    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)));
+    $this->assertText(t('entity_test @id has been created.', array('@id' => $id)));
 
     // Verify that the link is output according to the formatter settings.
     // Not using generatePermutations(), since that leads to 32 cases, which
@@ -297,7 +307,7 @@ function testLinkFormatter() {
         else {
           $display_options['settings'] = $new_value;
         }
-        entity_get_display('test_entity', 'test_bundle', 'full')
+        entity_get_display('entity_test', 'entity_test', 'full')
           ->setComponent($this->field['field_name'], $display_options)
           ->save();
 
@@ -365,8 +375,8 @@ function testLinkSeparateFormatter() {
     field_create_field($this->field);
     $this->instance = array(
       'field_name' => $this->field['field_name'],
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle',
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
       'settings' => array(
         'title' => DRUPAL_OPTIONAL,
       ),
@@ -379,7 +389,7 @@ function testLinkSeparateFormatter() {
       'label' => 'hidden',
     );
     field_create_instance($this->instance);
-    entity_get_display('test_entity', 'test_bundle', 'full')
+    entity_get_display('entity_test', 'entity_test', 'full')
       ->setComponent($this->field['field_name'], $display_options)
       ->save();
 
@@ -390,20 +400,22 @@ function testLinkSeparateFormatter() {
     // - The second field item uses a URL and title.
     // For consistency in assertion code below, the URL is assigned to the title
     // variable for the first field.
-    $this->drupalGet('test-entity/add/test_bundle');
+    $this->drupalGet('entity_test/add');
     $url1 = 'http://www.example.com/content/articles/archive?author=John&year=2012#com';
     $url2 = 'http://www.example.org/content/articles/archive?author=John&year=2012#org';
     // Intentionally contains an ampersand that needs sanitization on output.
     $title2 = 'A very long & strange example title that could break the nice layout of the site';
     $edit = array(
+      'user_id' => 1,
+      'name' => $this->randomName(),
       "{$this->field['field_name']}[$langcode][0][url]" => $url1,
       "{$this->field['field_name']}[$langcode][1][url]" => $url2,
       "{$this->field['field_name']}[$langcode][1][title]" => $title2,
     );
     $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
+    preg_match('|entity_test/manage/(\d+)/edit|', $this->url, $match);
     $id = $match[1];
-    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)));
+    $this->assertText(t('entity_test @id has been created.', array('@id' => $id)));
 
     // Verify that the link is output according to the formatter settings.
     $options = array(
@@ -415,7 +427,7 @@ function testLinkSeparateFormatter() {
       foreach ($values as $new_value) {
         // Update the field formatter settings.
         $display_options['settings'] = array($setting => $new_value);
-        entity_get_display('test_entity', 'test_bundle', 'full')
+        entity_get_display('entity_test', 'entity_test', 'full')
           ->setComponent($this->field['field_name'], $display_options)
           ->save();
 
@@ -468,11 +480,11 @@ function testLinkSeparateFormatter() {
    */
   protected function renderTestEntity($id, $view_mode = 'full', $reset = TRUE) {
     if ($reset) {
-      $this->container->get('plugin.manager.entity')->getStorageController('test_entity')->resetCache(array($id));
+      $this->container->get('plugin.manager.entity')->getStorageController('entity_test')->resetCache(array($id));
     }
-    $entity = field_test_entity_test_load($id);
+    $entity = entity_load('entity_test', $id);
     $display = entity_get_display($entity->entityType(), $entity->bundle(), $view_mode);
-    field_attach_prepare_view('test_entity', array($entity->id() => $entity), array($entity->bundle() => $display));
+    field_attach_prepare_view('entity_test', array($entity->id() => $entity), array($entity->bundle() => $display));
     $entity->content = field_attach_view($entity, $display);
 
     $output = drupal_render($entity->content);
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php
index 67c4eb4..2842cdc 100644
--- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php
@@ -115,7 +115,7 @@ function testContentTypeLanguageConfiguration() {
     $edit = array(
       'type' => $type2->type,
       'title' => $node_title,
-      'body' => array($langcode => array(array('value' => $node_body))),
+      'body' => array(array('value' => $node_body)),
       'langcode' => $langcode,
     );
     $node = $this->drupalCreateNode($edit);
diff --git a/core/modules/menu/menu.module b/core/modules/menu/menu.module
index c300ed6..1f2e970 100644
--- a/core/modules/menu/menu.module
+++ b/core/modules/menu/menu.module
@@ -11,7 +11,7 @@
  * URLs to be added to the main site navigation menu.
  */
 
-use Drupal\node\Plugin\Core\Entity\Node;
+use Drupal\Core\Entity\EntityInterface;
 use Drupal\block\Plugin\Core\Entity\Block;
 use Drupal\system\Plugin\Core\Entity\Menu;
 use Drupal\system\Plugin\block\block\SystemMenuBlock;
@@ -423,21 +423,21 @@ function menu_block_view_alter(array &$build, Block $block) {
 /**
  * Implements hook_node_insert().
  */
-function menu_node_insert(Node $node) {
+function menu_node_insert(EntityInterface $node) {
   menu_node_save($node);
 }
 
 /**
  * Implements hook_node_update().
  */
-function menu_node_update(Node $node) {
+function menu_node_update(EntityInterface $node) {
   menu_node_save($node);
 }
 
 /**
  * Helper for hook_node_insert() and hook_node_update().
  */
-function menu_node_save(Node $node) {
+function menu_node_save(EntityInterface $node) {
   if (isset($node->menu)) {
     $link = &$node->menu;
     if (empty($link['enabled'])) {
@@ -466,7 +466,7 @@ function menu_node_save(Node $node) {
 /**
  * Implements hook_node_predelete().
  */
-function menu_node_predelete(Node $node) {
+function menu_node_predelete(EntityInterface $node) {
   // Delete all menu module links that point to this node.
   $query = entity_query('menu_link')
     ->condition('link_path', 'node/' . $node->nid)
@@ -481,7 +481,7 @@ function menu_node_predelete(Node $node) {
 /**
  * Implements hook_node_prepare().
  */
-function menu_node_prepare(Node $node) {
+function menu_node_prepare(EntityInterface $node) {
   if (empty($node->menu)) {
     // Prepare the node for the edit form so that $node->menu always exists.
     $menu_name = strtok(variable_get('menu_parent_' . $node->type, 'main:0'), ':');
@@ -644,7 +644,7 @@ function menu_form_node_form_alter(&$form, $form_state) {
  *
  * @see menu_form_node_form_alter()
  */
-function menu_node_submit(Node $node, $form, $form_state) {
+function menu_node_submit(EntityInterface $node, $form, $form_state) {
   $node->menu = entity_create('menu_link', $form_state['values']['menu']);
   // Decompose the selected menu parent option into 'menu_name' and 'plid', if
   // the form used the default parent selection widget.
diff --git a/core/modules/node/lib/Drupal/node/NodeFormController.php b/core/modules/node/lib/Drupal/node/NodeFormController.php
index 63b4189..8e39c72 100644
--- a/core/modules/node/lib/Drupal/node/NodeFormController.php
+++ b/core/modules/node/lib/Drupal/node/NodeFormController.php
@@ -10,12 +10,12 @@
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Datetime\DrupalDateTime;
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Entity\EntityFormController;
+use Drupal\Core\Entity\EntityFormControllerNG;
 
 /**
  * Form controller for the node edit forms.
  */
-class NodeFormController extends EntityFormController {
+class NodeFormController extends EntityFormControllerNG {
 
   /**
    * Prepares the node object.
@@ -471,4 +471,19 @@ public function delete(array $form, array &$form_state) {
     $form_state['redirect'] = array('node/' . $node->nid . '/delete', array('query' => $destination));
   }
 
+  /**
+   * Implements \Drupal\Core\Entity\EntityFormControllerInterface::buildEntity().
+   */
+  public function buildEntity(array $form, array &$form_state) {
+    return parent::buildEntity($form, $form_state)->getBCEntity();
+  }
+
+  /**
+   * Implements \Drupal\Core\Entity\EntityFormControllerInterface::getEntity().
+   */
+  public function getEntity(array $form_state) {
+    $entity = parent::getEntity($form_state);
+    return isset($entity) ? $entity->getBCEntity() : $entity;
+  }
+
 }
diff --git a/core/modules/node/lib/Drupal/node/NodeStorageController.php b/core/modules/node/lib/Drupal/node/NodeStorageController.php
index d855384..c9e832e 100644
--- a/core/modules/node/lib/Drupal/node/NodeStorageController.php
+++ b/core/modules/node/lib/Drupal/node/NodeStorageController.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\node;
 
-use Drupal\Core\Entity\DatabaseStorageController;
+use Drupal\Core\Entity\DatabaseStorageControllerNG;
 use Drupal\Core\Entity\EntityInterface;
 
 /**
@@ -16,31 +16,40 @@
  * This extends the Drupal\Core\Entity\DatabaseStorageController class, adding
  * required special handling for node entities.
  */
-class NodeStorageController extends DatabaseStorageController {
+class NodeStorageController extends DatabaseStorageControllerNG {
 
   /**
    * Overrides Drupal\Core\Entity\DatabaseStorageController::create().
    */
   public function create(array $values) {
-    $node = parent::create($values);
-
-    // Set the created time to now.
-    if (empty($node->created)) {
-      $node->created = REQUEST_TIME;
+    // @todo Handle this through property defaults.
+    if (empty($values['created'])) {
+      $values['created'] = REQUEST_TIME;
     }
-
-    return $node;
+    return parent::create($values)->getBCEntity();
   }
 
   /**
-   * Overrides Drupal\Core\Entity\DatabaseStorageController::attachLoad().
+   * Overrides Drupal\Core\Entity\DatabaseStorageControllerNG::attachLoad().
    */
-  protected function attachLoad(&$nodes, $load_revision = FALSE) {
+  protected function attachLoad(&$queried_entities, $load_revision = FALSE) {
+    $nodes = $this->mapFromStorageRecords($queried_entities, $load_revision);
+
     // Create an array of nodes for each content type and pass this to the
-    // object type specific callback.
+    // object type specific callback. To preserve backward-compatibility we
+    // pass on BC decorators to node-specific hooks, while we pass on the
+    // regular entity objects else.
     $typed_nodes = array();
-    foreach ($nodes as $id => $entity) {
-      $typed_nodes[$entity->type][$id] = $entity;
+    foreach ($nodes as $id => $node) {
+      $queried_entities[$id] = $node->getBCEntity();
+      $typed_nodes[$node->bundle()][$id] = $queried_entities[$id];
+    }
+
+    if ($load_revision) {
+      field_attach_load_revision($this->entityType, $queried_entities);
+    }
+    else {
+      field_attach_load($this->entityType, $queried_entities);
     }
 
     // Call object type specific callbacks on each typed array of nodes.
@@ -55,7 +64,19 @@ protected function attachLoad(&$nodes, $load_revision = FALSE) {
     // hook_node_load(), containing a list of node types that were loaded.
     $argument = array_keys($typed_nodes);
     $this->hookLoadArguments = array($argument);
-    parent::attachLoad($nodes, $load_revision);
+
+    // Call hook_entity_load().
+    foreach (module_implements('entity_load') as $module) {
+      $function = $module . '_entity_load';
+      $function($queried_entities, $this->entityType);
+    }
+    // Call hook_TYPE_load(). The first argument for hook_TYPE_load() are
+    // always the queried entities, followed by additional arguments set in
+    // $this->hookLoadArguments.
+    $args = array_merge(array($queried_entities), $this->hookLoadArguments);
+    foreach (module_implements($this->entityType . '_load') as $module) {
+      call_user_func_array($module . '_' . $this->entityType . '_load', $args);
+    }
   }
 
   /**
@@ -77,6 +98,8 @@ protected function buildQuery($ids, $revision_id = FALSE) {
    * Overrides Drupal\Core\Entity\DatabaseStorageController::invokeHook().
    */
   protected function invokeHook($hook, EntityInterface $node) {
+    $node = $node->getBCEntity();
+
     if ($hook == 'insert' || $hook == 'update') {
       node_invoke($node, $hook);
     }
@@ -86,7 +109,23 @@ protected function invokeHook($hook, EntityInterface $node) {
       node_invoke($node, 'delete');
     }
 
-    parent::invokeHook($hook, $node);
+    // Inline parent::invokeHook() to pass on BC-entities to node-specific
+    // hooks.
+
+    $function = 'field_attach_' . $hook;
+    // @todo: field_attach_delete_revision() is named the wrong way round,
+    // consider renaming it.
+    if ($function == 'field_attach_revision_delete') {
+      $function = 'field_attach_delete_revision';
+    }
+    if (!empty($this->entityInfo['fieldable']) && function_exists($function)) {
+      $function($node);
+    }
+
+    // Invoke the hook.
+    module_invoke_all($this->entityType . '_' . $hook, $node);
+    // Invoke the respective entity-level hook.
+    module_invoke_all('entity_' . $hook, $node, $this->entityType);
   }
 
   /**
@@ -94,7 +133,7 @@ protected function invokeHook($hook, EntityInterface $node) {
    */
   protected function preSave(EntityInterface $node) {
     // Before saving the node, set changed and revision times.
-    $node->changed = REQUEST_TIME;
+    $node->changed->value = REQUEST_TIME;
   }
 
   /**
@@ -126,28 +165,29 @@ protected function preSaveRevision(\stdClass $record, EntityInterface $entity) {
 
     if ($entity->isNewRevision()) {
       $record->timestamp = REQUEST_TIME;
-      $record->uid = isset($record->revision_uid) ? $record->revision_uid : $GLOBALS['user']->uid;
+      $record->uid = isset($entity->revision_uid->value) ? $entity->revision_uid->value : $GLOBALS['user']->uid;
     }
   }
 
   /**
    * Overrides Drupal\Core\Entity\DatabaseStorageController::postSave().
    */
-  function postSave(EntityInterface $node, $update) {
+  public function postSave(EntityInterface $node, $update) {
     // Update the node access table for this node, but only if it is the
     // default revision. There's no need to delete existing records if the node
     // is new.
     if ($node->isDefaultRevision()) {
-      node_access_acquire_grants($node, $update);
+      node_access_acquire_grants($node->getBCEntity(), $update);
     }
   }
+
   /**
    * Overrides Drupal\Core\Entity\DatabaseStorageController::preDelete().
    */
-  function preDelete($entities) {
+  public function preDelete($entities) {
     if (module_exists('search')) {
       foreach ($entities as $id => $entity) {
-        search_reindex($entity->nid, 'node');
+        search_reindex($entity->nid->value, 'node');
       }
     }
   }
@@ -163,4 +203,110 @@ protected function postDelete($nodes) {
       ->condition('nid', $ids, 'IN')
       ->execute();
   }
+
+  /**
+   * Overrides \Drupal\Core\Entity\DataBaseStorageControllerNG::basePropertyDefinitions().
+   */
+  public function baseFieldDefinitions() {
+    $properties['nid'] = array(
+      'label' => t('Node ID'),
+      'description' => t('The node ID.'),
+      'type' => 'integer_field',
+      'read-only' => TRUE,
+    );
+    $properties['uuid'] = array(
+      'label' => t('UUID'),
+      'description' => t('The node UUID.'),
+      'type' => 'string_field',
+      'read-only' => TRUE,
+    );
+    $properties['vid'] = array(
+      'label' => t('Revision ID'),
+      'description' => t('The node revision ID.'),
+      'type' => 'integer_field',
+      'read-only' => TRUE,
+    );
+    $properties['type'] = array(
+      'label' => t('Type'),
+      'description' => t('The node type.'),
+      'type' => 'string_field',
+      'read-only' => TRUE,
+    );
+    $properties['langcode'] = array(
+      'label' => t('Language code'),
+      'description' => t('The node language code.'),
+      'type' => 'language_field',
+    );
+    $properties['title'] = array(
+      'label' => t('Title'),
+      'description' => t('The title of this node, always treated as non-markup plain text.'),
+      'type' => 'string_field',
+    );
+    $properties['uid'] = array(
+      'label' => t('User ID'),
+      'description' => t('The user ID of the node author.'),
+      'type' => 'entity_reference_field',
+      'settings' => array('target_type' => 'user'),
+    );
+    $properties['status'] = array(
+      'label' => t('Publishing status'),
+      'description' => t('A boolean indicating whether the node is published.'),
+      'type' => 'boolean_field',
+    );
+    $properties['created'] = array(
+      'label' => t('Created'),
+      'description' => t('The time that the node was created.'),
+      'type' => 'integer_field',
+    );
+    $properties['changed'] = array(
+      'label' => t('Changed'),
+      'description' => t('The time that the node was last edited.'),
+      'type' => 'integer_field',
+    );
+    $properties['comment'] = array(
+      'label' => t('Comment'),
+      'description' => t('Whether comments are allowed on this node: 0 = no, 1 = closed (read only), 2 = open (read/write).'),
+      'type' => 'integer_field',
+    );
+    $properties['promote'] = array(
+      'label' => t('Promote'),
+      'description' => t('A boolean indicating whether the node should be displayed on the front page.'),
+      'type' => 'boolean_field',
+    );
+    $properties['sticky'] = array(
+      'label' => t('Sticky'),
+      'description' => t('A boolean indicating whether the node should be displayed at the top of lists in which it appears.'),
+      'type' => 'boolean_field',
+    );
+    $properties['tnid'] = array(
+      'label' => t('Translation set ID'),
+      'description' => t('The translation set id for this node, which equals the node id of the source post in each set.'),
+      'type' => 'integer_field',
+    );
+    $properties['translate'] = array(
+      'label' => t('Translate'),
+      'description' => t('A boolean indicating whether this translation page needs to be updated.'),
+      'type' => 'boolean_field',
+    );
+    $properties['revision_timestamp'] = array(
+      'label' => t('Revision timestamp'),
+      'description' => t('The time that the current revision was created.'),
+      'type' => 'integer_field',
+      'queryable' => FALSE,
+    );
+    $properties['revision_uid'] = array(
+      'label' => t('Revision user ID'),
+      'description' => t('The user ID of the author of the current revision.'),
+      'type' => 'entity_reference_field',
+      'settings' => array('target_type' => 'user'),
+      'queryable' => FALSE,
+    );
+    $properties['log'] = array(
+      'label' => t('Log'),
+      'description' => t('The log entry explaining the changes in this version.'),
+      'type' => 'string_field',
+    );
+    return $properties;
+  }
+
 }
diff --git a/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php b/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php
index a4cf264..c303227 100644
--- a/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php
+++ b/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php
@@ -8,7 +8,7 @@
 namespace Drupal\node\Plugin\Core\Entity;
 
 use Drupal\Core\Entity\ContentEntityInterface;
-use Drupal\Core\Entity\Entity;
+use Drupal\Core\Entity\EntityNG;
 use Drupal\Core\Annotation\Plugin;
 use Drupal\Core\Annotation\Translation;
 
@@ -43,64 +43,54 @@
  *   permission_granularity = "bundle"
  * )
  */
-class Node extends Entity implements ContentEntityInterface {
+class Node extends EntityNG implements ContentEntityInterface {
 
   /**
    * The node ID.
    *
-   * @var integer
+   * @var \Drupal\Core\Entity\Field\FieldInterface
    */
   public $nid;
 
   /**
    * The node revision ID.
    *
-   * @var integer
+   * @var \Drupal\Core\Entity\Field\FieldInterface
    */
   public $vid;
 
   /**
-   * Indicates whether this is the default node revision.
-   *
-   * The default revision of a node is the one loaded when no specific revision
-   * has been specified. Only default revisions are saved to the node table.
-   *
-   * @var boolean
-   */
-  public $isDefaultRevision = TRUE;
-
-  /**
    * The node UUID.
    *
-   * @var string
+   * @var \Drupal\Core\Entity\Field\FieldInterface
    */
   public $uuid;
 
   /**
    * The node content type (bundle).
    *
-   * @var string
+   * @var \Drupal\Core\Entity\Field\FieldInterface
    */
   public $type;
 
   /**
    * The node language code.
    *
-   * @var string
+   * @var \Drupal\Core\Entity\Field\FieldInterface
    */
-  public $langcode = LANGUAGE_NOT_SPECIFIED;
+  public $langcode;
 
   /**
    * The node title.
    *
-   * @var string
+   * @var \Drupal\Core\Entity\Field\FieldInterface
    */
   public $title;
 
   /**
    * The node owner's user ID.
    *
-   * @var integer
+   * @var \Drupal\Core\Entity\Field\FieldInterface
    */
   public $uid;
 
@@ -110,21 +100,21 @@ class Node extends Entity implements ContentEntityInterface {
    * Unpublished nodes are only visible to their authors and to administrators.
    * The value is either NODE_PUBLISHED or NODE_NOT_PUBLISHED.
    *
-   * @var integer
+   * @var \Drupal\Core\Entity\Field\FieldInterface
    */
   public $status;
 
   /**
    * The node creation timestamp.
    *
-   * @var integer
+   * @var \Drupal\Core\Entity\Field\FieldInterface
    */
   public $created;
 
   /**
    * The node modification timestamp.
    *
-   * @var integer
+   * @var \Drupal\Core\Entity\Field\FieldInterface
    */
   public $changed;
 
@@ -135,7 +125,7 @@ class Node extends Entity implements ContentEntityInterface {
    * COMMENT_NODE_CLOSED => comments are read-only
    * COMMENT_NODE_OPEN => open (read/write)
    *
-   * @var integer
+   * @var \Drupal\Core\Entity\Field\FieldInterface
    */
   public $comment;
 
@@ -145,7 +135,7 @@ class Node extends Entity implements ContentEntityInterface {
    * Promoted nodes should be displayed on the front page of the site. The value
    * is either NODE_PROMOTED or NODE_NOT_PROMOTED.
    *
-   * @var integer
+   * @var \Drupal\Core\Entity\Field\FieldInterface
    */
   public $promote;
 
@@ -155,7 +145,7 @@ class Node extends Entity implements ContentEntityInterface {
    * Sticky nodes should be displayed at the top of lists in which they appear.
    * The value is either NODE_STICKY or NODE_NOT_STICKY.
    *
-   * @var integer
+   * @var \Drupal\Core\Entity\Field\FieldInterface
    */
   public $sticky;
 
@@ -165,7 +155,7 @@ class Node extends Entity implements ContentEntityInterface {
    * Translations sets are based on the ID of the node containing the source
    * text for the translation set.
    *
-   * @var integer
+   * @var \Drupal\Core\Entity\Field\FieldInterface
    */
   public $tnid;
 
@@ -174,52 +164,61 @@ class Node extends Entity implements ContentEntityInterface {
    *
    * If the translation page needs to be updated, the value is 1; otherwise 0.
    *
-   * @var integer
+   * @var \Drupal\Core\Entity\Field\FieldInterface
    */
   public $translate;
 
   /**
    * The node revision creation timestamp.
    *
-   * @var integer
+   * @var \Drupal\Core\Entity\Field\FieldInterface
    */
   public $revision_timestamp;
 
   /**
    * The node revision author's user ID.
    *
-   * @var integer
+   * @var \Drupal\Core\Entity\Field\FieldInterface
    */
   public $revision_uid;
 
   /**
-   * Implements Drupal\Core\Entity\EntityInterface::id().
-   */
-  public function id() {
-    return $this->nid;
-  }
-
-  /**
-   * Implements Drupal\Core\Entity\EntityInterface::bundle().
-   */
-  public function bundle() {
-    return $this->type;
+   * Overrides \Drupal\Core\Entity\EntityNG::init().
+   */
+  protected function init() {
+    parent::init();
+    // We unset all defined properties, so magic getters apply.
+    unset($this->nid);
+    unset($this->vid);
+    unset($this->uuid);
+    unset($this->type);
+    unset($this->title);
+    unset($this->uid);
+    unset($this->status);
+    unset($this->created);
+    unset($this->changed);
+    unset($this->comment);
+    unset($this->promote);
+    unset($this->sticky);
+    unset($this->tnid);
+    unset($this->translate);
+    unset($this->revision_timestamp);
+    unset($this->revision_uid);
+    unset($this->log);
   }
 
   /**
-   * Overrides Drupal\Core\Entity\Entity::createDuplicate().
+   * Implements Drupal\Core\Entity\EntityInterface::id().
    */
-  public function createDuplicate() {
-    $duplicate = parent::createDuplicate();
-    $duplicate->vid = NULL;
-    return $duplicate;
+  public function id() {
+    return $this->get('nid')->value;
   }
 
   /**
    * Overrides Drupal\Core\Entity\Entity::getRevisionId().
    */
   public function getRevisionId() {
-    return $this->vid;
+    return $this->get('vid')->value;
   }
 
 }
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeAccessFieldTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeAccessFieldTest.php
index 433c6bb..0db0bda 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeAccessFieldTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeAccessFieldTest.php
@@ -57,7 +57,7 @@ function testNodeAccessAdministerField() {
     // Create a page node.
     $langcode = LANGUAGE_NOT_SPECIFIED;
     $field_data = array();
-    $value = $field_data[$langcode][0]['value'] = $this->randomName();
+    $value = $field_data[0]['value'] = $this->randomName();
     $node = $this->drupalCreateNode(array($this->field_name => $field_data));
 
     // Log in as the administrator and confirm that the field value is present.
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeAccessLanguageTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeAccessLanguageTest.php
index 6ff6ae0..efd2b70 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeAccessLanguageTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeAccessLanguageTest.php
@@ -64,7 +64,7 @@ function testNodeAccess() {
 
     // Tests the default access provided for a published Hungarian node.
     $web_user = $this->drupalCreateUser(array('access content'));
-    $node = $this->drupalCreateNode(array('body' => array('hu' => array(array())), 'langcode' => 'hu'));
+    $node = $this->drupalCreateNode(array('body' => array(array()), 'langcode' => 'hu'));
     $this->assertTrue($node->langcode == 'hu', 'Node created as Hungarian.');
     $expected_node_access = array('view' => TRUE, 'update' => FALSE, 'delete' => FALSE);
     $this->assertNodeAccess($expected_node_access, $node, $web_user);
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeAccessPagerTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeAccessPagerTest.php
index de24f45..a9ae1c3 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeAccessPagerTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeAccessPagerTest.php
@@ -86,9 +86,7 @@ public function testForumPager() {
         'nid' => NULL,
         'type' => 'forum',
         'taxonomy_forums' => array(
-          LANGUAGE_NOT_SPECIFIED => array(
-            array('tid' => $tid, 'vid' => $vid),
-          ),
+          array('tid' => $tid)
         ),
       ));
     }
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeEntityFieldQueryAlterTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeEntityFieldQueryAlterTest.php
index 2333dd9..9cc80f7 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeEntityFieldQueryAlterTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeEntityFieldQueryAlterTest.php
@@ -50,7 +50,7 @@ function setUp() {
         'value' => 'A' . $this->randomName(32),
         'format' => filter_default_format(),
       );
-      $settings['body'][LANGUAGE_NOT_SPECIFIED][0] = $body;
+      $settings['body'][0] = $body;
       $this->drupalCreateNode($settings);
     }
 
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeFieldMultilingualTestCase.php b/core/modules/node/lib/Drupal/node/Tests/NodeFieldMultilingualTestCase.php
index 6ea519a..f382457 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeFieldMultilingualTestCase.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeFieldMultilingualTestCase.php
@@ -82,33 +82,30 @@ function testMultilingualNodeForm() {
     $this->drupalPost('node/add/page', $edit, t('Save'));
 
     // Check that the node exists in the database.
-    $node = $this->drupalGetNodeByTitle($edit[$title_key]);
+    $node = $this->drupalGetNodeByTitle($edit[$title_key])->getOriginalEntity();
     $this->assertTrue($node, 'Node found in database.');
-
-    $assert = isset($node->body['en']) && !isset($node->body[LANGUAGE_NOT_SPECIFIED]) && $node->body['en'][0]['value'] == $body_value;
-    $this->assertTrue($assert, 'Field language correctly set.');
+    $this->assertTrue($node->language()->langcode == $langcode && $node->body->value == $body_value, 'Field language correctly set.');
 
     // Change node language.
-    $this->drupalGet("node/$node->nid/edit");
+    $langcode = 'it';
+    $this->drupalGet("node/{$node->id()}/edit");
     $edit = array(
       $title_key => $this->randomName(8),
-      'langcode' => 'it'
+      'langcode' => $langcode,
     );
     $this->drupalPost(NULL, $edit, t('Save'));
-    $node = $this->drupalGetNodeByTitle($edit[$title_key], TRUE);
+    $node = $this->drupalGetNodeByTitle($edit[$title_key], TRUE)->getOriginalEntity();
     $this->assertTrue($node, 'Node found in database.');
-
-    $assert = isset($node->body['it']) && !isset($node->body['en']) && $node->body['it'][0]['value'] == $body_value;
-    $this->assertTrue($assert, 'Field language correctly changed.');
+    $this->assertTrue($node->language()->langcode == $langcode && $node->body->value == $body_value, 'Field language correctly changed.');
 
     // Enable content language URL detection.
     language_negotiation_set(LANGUAGE_TYPE_CONTENT, array(LANGUAGE_NEGOTIATION_URL => 0));
 
     // Test multilingual field language fallback logic.
-    $this->drupalGet("it/node/$node->nid");
+    $this->drupalGet("it/node/{$node->id()}");
     $this->assertRaw($body_value, 'Body correctly displayed using Italian as requested language');
 
-    $this->drupalGet("node/$node->nid");
+    $this->drupalGet("node/{$node->id()}");
     $this->assertRaw($body_value, 'Body correctly displayed using English as requested language');
   }
 
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeRevisionPermissionsTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeRevisionPermissionsTest.php
index 53b9d94..dfdccdf 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeRevisionPermissionsTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeRevisionPermissionsTest.php
@@ -49,7 +49,7 @@ function setUp() {
       for ($i = 0; $i < 3; $i++) {
         // Create a revision for the same nid and settings with a random log.
         $revision = clone $nodes[$type];
-        $revision->revision = 1;
+        $revision->setNewRevision();
         $revision->log = $this->randomName(32);
         node_save($revision);
         $this->node_revisions[$type][] = $revision;
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeRevisionsAllTestCase.php b/core/modules/node/lib/Drupal/node/Tests/NodeRevisionsAllTestCase.php
index 655c4c1..90a7305 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeRevisionsAllTestCase.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeRevisionsAllTestCase.php
@@ -48,18 +48,24 @@ function setUp() {
     $logs = array();
 
     // Get the original node.
-    $nodes[] = $node;
+    $nodes[] = clone $node;
 
     // Create three revisions.
     $revision_count = 3;
     for ($i = 0; $i < $revision_count; $i++) {
-      $logs[] = $settings['log'] = $this->randomName(32);
+      $logs[] = $node->log = $this->randomName(32);
 
       // Create revision with a random title and body and update variables.
-      $this->drupalCreateNode($settings);
-      $node = node_load($node->nid); // Make sure we get revision information.
-      $settings = get_object_vars($node);
-      $nodes[] = $node;
+      $node->title = $this->randomName();
+      $node->body[$node->language()->langcode][0] = array(
+        'value' => $this->randomName(32),
+        'format' => filter_default_format(),
+      );
+      $node->setNewRevision();
+      $node->save();
+
+      $node = node_load($node->nid, TRUE); // Make sure we get revision information.
+      $nodes[] = clone $node;
     }
 
     $this->nodes = $nodes;
@@ -110,7 +116,7 @@ function testRevisions() {
         '%revision-date' => format_date($nodes[1]->revision_timestamp)
       )),
       'Revision reverted.');
-    $reverted_node = node_load($node->nid);
+    $reverted_node = node_load($node->nid, TRUE);
     $this->assertTrue(($nodes[1]->body[LANGUAGE_NOT_SPECIFIED][0]['value'] == $reverted_node->body[LANGUAGE_NOT_SPECIFIED][0]['value']), t('Node reverted correctly.'));
 
     // Confirm that this is not the current version.
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeRevisionsTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeRevisionsTest.php
index d5ea7b5..46244b8 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeRevisionsTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeRevisionsTest.php
@@ -48,20 +48,24 @@ function setUp() {
     $logs = array();
 
     // Get original node.
-    $nodes[] = $node;
+    $nodes[] = clone $node;
 
     // Create three revisions.
     $revision_count = 3;
     for ($i = 0; $i < $revision_count; $i++) {
-      $logs[] = $settings['log'] = $this->randomName(32);
+      $logs[] = $node->log = $this->randomName(32);
 
-      // Create revision with random title and body and update variables.
-      $this->drupalCreateNode($settings);
-      $node = node_load($node->nid); // Make sure we get revision information.
-      $settings = get_object_vars($node);
-      $settings['isDefaultRevision'] = TRUE;
+      // Create revision with a random title and body and update variables.
+      $node->title = $this->randomName();
+      $node->body[$node->language()->langcode][0] = array(
+        'value' => $this->randomName(32),
+        'format' => filter_default_format(),
+      );
+      $node->setNewRevision();
+      $node->save();
 
-      $nodes[] = $node;
+      $node = node_load($node->nid); // Make sure we get revision information.
+      $nodes[] = clone $node;
     }
 
     $this->nodes = $nodes;
@@ -96,7 +100,7 @@ function testRevisions() {
     $this->assertRaw(t('@type %title has been reverted back to the revision from %revision-date.',
                         array('@type' => 'Basic page', '%title' => $nodes[1]->label(),
                               '%revision-date' => format_date($nodes[1]->revision_timestamp))), 'Revision reverted.');
-    $reverted_node = node_load($node->nid);
+    $reverted_node = node_load($node->nid, TRUE);
     $this->assertTrue(($nodes[1]->body[LANGUAGE_NOT_SPECIFIED][0]['value'] == $reverted_node->body[LANGUAGE_NOT_SPECIFIED][0]['value']), 'Node reverted correctly.');
 
     // Confirm that this is not the default version.
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeSaveTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeSaveTest.php
index f86bc52..e2f5f29 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeSaveTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeSaveTest.php
@@ -51,13 +51,13 @@ function testImport() {
     $title = $this->randomName(8);
     $node = array(
       'title' => $title,
-      'body' => array(LANGUAGE_NOT_SPECIFIED => array(array('value' => $this->randomName(32)))),
+      'body' => array(array('value' => $this->randomName(32))),
       'uid' => $this->web_user->uid,
       'type' => 'article',
       'nid' => $test_nid,
-      'enforceIsNew' => TRUE,
     );
     $node = node_submit(entity_create('node', $node));
+    $node->enforceIsNew();
 
     // Verify that node_submit did not overwrite the user ID.
     $this->assertEqual($node->uid, $this->web_user->uid, 'Function node_submit() preserves user ID');
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeTokenReplaceTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeTokenReplaceTest.php
index 452f0f4..d17de34 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeTokenReplaceTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeTokenReplaceTest.php
@@ -35,7 +35,7 @@ function testNodeTokenReplacement() {
       'type' => 'article',
       'uid' => $account->uid,
       'title' => '<blink>Blinking Text</blink>',
-      'body' => array(LANGUAGE_NOT_SPECIFIED => array(array('value' => $this->randomName(32), 'summary' => $this->randomName(16)))),
+      'body' => array(array('value' => $this->randomName(32), 'summary' => $this->randomName(16))),
     );
     $node = $this->drupalCreateNode($settings);
 
@@ -83,7 +83,7 @@ function testNodeTokenReplacement() {
     }
 
     // Repeat for a node without a summary.
-    $settings['body'] = array(LANGUAGE_NOT_SPECIFIED => array(array('value' => $this->randomName(32), 'summary' => '')));
+    $settings['body'] = array(array('value' => $this->randomName(32), 'summary' => ''));
     $node = $this->drupalCreateNode($settings);
 
     // Load node (without summary) so that the body and summary fields are
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeTranslationUITest.php b/core/modules/node/lib/Drupal/node/Tests/NodeTranslationUITest.php
index 8a744ec..3965ca4 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeTranslationUITest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeTranslationUITest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\node\Tests;
 
+use Drupal\Core\Entity\EntityInterface;
 use Drupal\translation_entity\Tests\EntityTranslationUITest;
 
 /**
@@ -67,7 +68,10 @@ protected function getNewEntityValues($langcode) {
   /**
    * Overrides \Drupal\translation_entity\Tests\EntityTranslationUITest::getFormSubmitAction().
    */
-  protected function getFormSubmitAction() {
+  protected function getFormSubmitAction(EntityInterface $entity) {
+    if ($entity->status) {
+      return t('Save and unpublish');
+    }
     return t('Save and keep unpublished');
   }
 
@@ -124,7 +128,7 @@ protected function assertAuthoringInfo() {
         'date[date]' => format_date($values[$langcode]['created'], 'custom', 'Y-m-d'),
         'date[time]' => format_date($values[$langcode]['created'], 'custom', 'H:i:s'),
       );
-      $this->drupalPost($path, $edit, $this->getFormSubmitAction(), array('language' => $languages[$langcode]));
+      $this->drupalPost($path, $edit, $this->getFormSubmitAction($entity), array('language' => $languages[$langcode]));
     }
 
     $entity = entity_load($this->entityType, $this->entityId, TRUE);
diff --git a/core/modules/node/lib/Drupal/node/Tests/SummaryLengthTest.php b/core/modules/node/lib/Drupal/node/Tests/SummaryLengthTest.php
index ee6ebe5..e627c6e 100644
--- a/core/modules/node/lib/Drupal/node/Tests/SummaryLengthTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/SummaryLengthTest.php
@@ -25,7 +25,7 @@ public static function getInfo() {
   function testSummaryLength() {
     // Create a node to view.
     $settings = array(
-      'body' => array(LANGUAGE_NOT_SPECIFIED => array(array('value' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam vitae arcu at leo cursus laoreet. Curabitur dui tortor, adipiscing malesuada tempor in, bibendum ac diam. Cras non tellus a libero pellentesque condimentum. What is a Drupalism? Suspendisse ac lacus libero. Ut non est vel nisl faucibus interdum nec sed leo. Pellentesque sem risus, vulputate eu semper eget, auctor in libero. Ut fermentum est vitae metus convallis scelerisque. Phasellus pellentesque rhoncus tellus, eu dignissim purus posuere id. Quisque eu fringilla ligula. Morbi ullamcorper, lorem et mattis egestas, tortor neque pretium velit, eget eleifend odio turpis eu purus. Donec vitae metus quis leo pretium tincidunt a pulvinar sem. Morbi adipiscing laoreet mauris vel placerat. Nullam elementum, nisl sit amet scelerisque malesuada, dolor nunc hendrerit quam, eu ultrices erat est in orci. Curabitur feugiat egestas nisl sed accumsan.'))),
+      'body' => array(array('value' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam vitae arcu at leo cursus laoreet. Curabitur dui tortor, adipiscing malesuada tempor in, bibendum ac diam. Cras non tellus a libero pellentesque condimentum. What is a Drupalism? Suspendisse ac lacus libero. Ut non est vel nisl faucibus interdum nec sed leo. Pellentesque sem risus, vulputate eu semper eget, auctor in libero. Ut fermentum est vitae metus convallis scelerisque. Phasellus pellentesque rhoncus tellus, eu dignissim purus posuere id. Quisque eu fringilla ligula. Morbi ullamcorper, lorem et mattis egestas, tortor neque pretium velit, eget eleifend odio turpis eu purus. Donec vitae metus quis leo pretium tincidunt a pulvinar sem. Morbi adipiscing laoreet mauris vel placerat. Nullam elementum, nisl sit amet scelerisque malesuada, dolor nunc hendrerit quam, eu ultrices erat est in orci. Curabitur feugiat egestas nisl sed accumsan.')),
       'promote' => 1,
     );
     $node = $this->drupalCreateNode($settings);
diff --git a/core/modules/node/node.api.php b/core/modules/node/node.api.php
index 1207238..d5e396c 100644
--- a/core/modules/node/node.api.php
+++ b/core/modules/node/node.api.php
@@ -256,7 +256,7 @@ function hook_node_grants($account, $op) {
  *
  * Note: a deny all grant is not written to the database; denies are implicit.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node that has just been saved.
  *
  * @return
@@ -266,7 +266,7 @@ function hook_node_grants($account, $op) {
  * @see hook_node_access_records_alter()
  * @ingroup node_access
  */
-function hook_node_access_records(Drupal\node\Node $node) {
+function hook_node_access_records(\Drupal\Core\Entity\EntityInterface $node) {
   // We only care about the node if it has been marked private. If not, it is
   // treated just like any other node and we completely ignore it.
   if ($node->private) {
@@ -317,7 +317,7 @@ function hook_node_access_records(Drupal\node\Node $node) {
  *
  * @param $grants
  *   The $grants array returned by hook_node_access_records().
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node for which the grants were acquired.
  *
  * The preferred use of this hook is in a module that bridges multiple node
@@ -329,7 +329,7 @@ function hook_node_access_records(Drupal\node\Node $node) {
  * @see hook_node_grants_alter()
  * @ingroup node_access
  */
-function hook_node_access_records_alter(&$grants, Drupal\node\Node $node) {
+function hook_node_access_records_alter(&$grants, Drupal\Core\Entity\EntityInterface $node) {
   // Our module allows editors to mark specific articles with the 'is_preview'
   // field. If the node being saved has a TRUE value for that field, then only
   // our grants are retained, and other grants are removed. Doing so ensures
@@ -459,14 +459,14 @@ function hook_node_operations() {
  * field_attach_delete() are called, and before the node is removed from the
  * node table in the database.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node that is about to be deleted.
  *
  * @see hook_node_predelete()
  * @see node_delete_multiple()
  * @ingroup node_api_hooks
  */
-function hook_node_predelete(Drupal\node\Node $node) {
+function hook_node_predelete(\Drupal\Core\Entity\EntityInterface $node) {
   db_delete('mytable')
     ->condition('nid', $node->nid)
     ->execute();
@@ -478,14 +478,14 @@ function hook_node_predelete(Drupal\node\Node $node) {
  * This hook is invoked from node_delete_multiple() after field_attach_delete()
  * has been called and after the node has been removed from the database.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node that has been deleted.
  *
  * @see hook_node_predelete()
  * @see node_delete_multiple()
  * @ingroup node_api_hooks
  */
-function hook_node_delete(Drupal\node\Node $node) {
+function hook_node_delete(\Drupal\Core\Entity\EntityInterface $node) {
   drupal_set_message(t('Node: @title has been deleted', array('@title' => $node->label())));
 }
 
@@ -496,12 +496,12 @@ function hook_node_delete(Drupal\node\Node $node) {
  * removed from the node_revision table, and before
  * field_attach_delete_revision() is called.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node revision (node object) that is being deleted.
  *
  * @ingroup node_api_hooks
  */
-function hook_node_revision_delete(Drupal\node\Node $node) {
+function hook_node_revision_delete(\Drupal\Core\Entity\EntityInterface $node) {
   db_delete('mytable')
     ->condition('vid', $node->vid)
     ->execute();
@@ -523,12 +523,12 @@ function hook_node_revision_delete(Drupal\node\Node $node) {
  * write/update database queries executed from this hook are also not committed
  * immediately. Check node_save() and db_transaction() for more info.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node that is being created.
  *
  * @ingroup node_api_hooks
  */
-function hook_node_insert(Drupal\node\Node $node) {
+function hook_node_insert(\Drupal\Core\Entity\EntityInterface $node) {
   db_insert('mytable')
     ->fields(array(
       'nid' => $node->nid,
@@ -543,12 +543,12 @@ function hook_node_insert(Drupal\node\Node $node) {
  * This hook runs after a new node object has just been instantiated. It can be
  * used to set initial values, e.g. to provide defaults.
  *
- * @param \Drupal\node\Plugin\Core\Entity\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node object.
  *
  * @ingroup node_api_hooks
  */
-function hook_node_create(\Drupal\node\Plugin\Core\Entity\Node $node) {
+function hook_node_create(\Drupal\Core\Entity\EntityInterface $node) {
   if (!isset($node->foo)) {
     $node->foo = 'some_initial_value';
   }
@@ -615,7 +615,7 @@ function hook_node_load($nodes, $types) {
  * the default home page at path 'node', a recent content block, etc.) See
  * @link node_access Node access rights @endlink for a full explanation.
  *
- * @param Drupal\node\Node|string $node
+ * @param Drupal\Core\Entity\EntityInterface|string $node
  *   Either a node entity or the machine name of the content type on which to
  *   perform the access check.
  * @param string $op
@@ -669,12 +669,12 @@ function hook_node_access($node, $op, $account, $langcode) {
  * This hook is invoked from NodeFormController::prepareEntity() after the
  * type-specific hook_prepare() is invoked.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node that is about to be shown on the add/edit form.
  *
  * @ingroup node_api_hooks
  */
-function hook_node_prepare(Drupal\node\Node $node) {
+function hook_node_prepare(\Drupal\Core\Entity\EntityInterface $node) {
   if (!isset($node->comment)) {
     $node->comment = variable_get("comment_$node->type", COMMENT_NODE_OPEN);
   }
@@ -686,7 +686,7 @@ function hook_node_prepare(Drupal\node\Node $node) {
  * This hook is invoked from node_search_execute(), after node_load() and
  * node_view() have been called.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node being displayed in a search result.
  * @param $langcode
  *   Language code of result being displayed.
@@ -702,7 +702,7 @@ function hook_node_prepare(Drupal\node\Node $node) {
  *
  * @ingroup node_api_hooks
  */
-function hook_node_search_result(Drupal\node\Node $node, $langcode) {
+function hook_node_search_result(\Drupal\Core\Entity\EntityInterface $node, $langcode) {
   $comments = db_query('SELECT comment_count FROM {node_comment_statistics} WHERE nid = :nid', array('nid' => $node->nid))->fetchField();
   return array('comment' => format_plural($comments, '1 comment', '@count comments'));
 }
@@ -713,12 +713,12 @@ function hook_node_search_result(Drupal\node\Node $node, $langcode) {
  * This hook is invoked from node_save() before the node is saved to the
  * database.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node that is being inserted or updated.
  *
  * @ingroup node_api_hooks
  */
-function hook_node_presave(Drupal\node\Node $node) {
+function hook_node_presave(\Drupal\Core\Entity\EntityInterface $node) {
   if ($node->nid && $node->moderate) {
     // Reset votes when node is updated:
     $node->score = 0;
@@ -743,12 +743,12 @@ function hook_node_presave(Drupal\node\Node $node) {
  * write/update database queries executed from this hook are also not committed
  * immediately. Check node_save() and db_transaction() for more info.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node that is being updated.
  *
  * @ingroup node_api_hooks
  */
-function hook_node_update(Drupal\node\Node $node) {
+function hook_node_update(\Drupal\Core\Entity\EntityInterface $node) {
   db_update('mytable')
     ->fields(array('extra' => $node->extra))
     ->condition('nid', $node->nid)
@@ -761,7 +761,7 @@ function hook_node_update(Drupal\node\Node $node) {
  * This hook is invoked during search indexing, after node_load(), and after the
  * result of node_view() is added as $node->rendered to the node object.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node being indexed.
  * @param $langcode
  *   Language code of the variant of the node being indexed.
@@ -771,7 +771,7 @@ function hook_node_update(Drupal\node\Node $node) {
  *
  * @ingroup node_api_hooks
  */
-function hook_node_update_index(Drupal\node\Node $node, $langcode) {
+function hook_node_update_index(\Drupal\Core\Entity\EntityInterface $node, $langcode) {
   $text = '';
   $comments = db_query('SELECT subject, comment, format FROM {comment} WHERE nid = :nid AND status = :status', array(':nid' => $node->nid, ':status' => COMMENT_PUBLISHED));
   foreach ($comments as $comment) {
@@ -795,7 +795,7 @@ function hook_node_update_index(Drupal\node\Node $node, $langcode) {
  * hook_node_presave() instead. If it is really necessary to change the node at
  * the validate stage, you can use form_set_value().
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node being validated.
  * @param $form
  *   The form being used to edit the node.
@@ -804,7 +804,7 @@ function hook_node_update_index(Drupal\node\Node $node, $langcode) {
  *
  * @ingroup node_api_hooks
  */
-function hook_node_validate(Drupal\node\Node $node, $form, &$form_state) {
+function hook_node_validate(\Drupal\Core\Entity\EntityInterface $node, $form, &$form_state) {
   if (isset($node->end) && isset($node->start)) {
     if ($node->start > $node->end) {
       form_set_error('time', t('An event may not end before it starts.'));
@@ -823,7 +823,7 @@ function hook_node_validate(Drupal\node\Node $node, $form, &$form_state) {
  * properties. See hook_field_attach_extract_form_values() for customizing
  * field-related properties.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node entity being updated in response to a form submission.
  * @param $form
  *   The form being used to edit the node.
@@ -832,7 +832,7 @@ function hook_node_validate(Drupal\node\Node $node, $form, &$form_state) {
  *
  * @ingroup node_api_hooks
  */
-function hook_node_submit(Drupal\node\Node $node, $form, &$form_state) {
+function hook_node_submit(\Drupal\Core\Entity\EntityInterface $node, $form, &$form_state) {
   // Decompose the selected menu parent option into 'menu_name' and 'plid', if
   // the form used the default parent selection widget.
   if (!empty($form_state['values']['menu']['parent'])) {
@@ -852,7 +852,7 @@ function hook_node_submit(Drupal\node\Node $node, $form, &$form_state) {
  * the RSS item generated for this node.
  * For details on how this is used, see node_feed().
  *
- * @param \Drupal\node\Plugin\Core\Entity\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node that is being assembled for rendering.
  * @param \Drupal\entity\Plugin\Core\Entity\EntityDisplay $display
  *   The entity_display object holding the display options configured for the
@@ -868,7 +868,7 @@ function hook_node_submit(Drupal\node\Node $node, $form, &$form_state) {
  *
  * @ingroup node_api_hooks
  */
-function hook_node_view(\Drupal\node\Plugin\Core\Entity\Node $node, \Drupal\entity\Plugin\Core\Entity\EntityDisplay $display, $view_mode, $langcode) {
+function hook_node_view(\Drupal\Core\Entity\EntityInterface $node, \Drupal\entity\Plugin\Core\Entity\EntityDisplay $display, $view_mode, $langcode) {
   // Only do the extra work if the component is configured to be displayed.
   // This assumes a 'mymodule_addition' extra field has been defined for the
   // node type in hook_field_extra_fields().
@@ -895,7 +895,7 @@ function hook_node_view(\Drupal\node\Plugin\Core\Entity\Node $node, \Drupal\enti
  *
  * @param $build
  *   A renderable array representing the node content.
- * @param \Drupal\node\Plugin\Core\Entity\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node being rendered.
  * @param \Drupal\entity\Plugin\Core\Entity\EntityDisplay $display
  *   The entity_display object holding the display options configured for the
@@ -906,7 +906,7 @@ function hook_node_view(\Drupal\node\Plugin\Core\Entity\Node $node, \Drupal\enti
  *
  * @ingroup node_api_hooks
  */
-function hook_node_view_alter(&$build, \Drupal\node\Plugin\Core\Entity\Node $node, \Drupal\entity\Plugin\Core\Entity\EntityDisplay $display) {
+function hook_node_view_alter(&$build, \Drupal\Core\Entity\EntityInterface $node, \Drupal\entity\Plugin\Core\Entity\EntityDisplay $display) {
   if ($build['#view_mode'] == 'full' && isset($build['an_additional_field'])) {
     // Change its weight.
     $build['an_additional_field']['#weight'] = -10;
@@ -1088,12 +1088,12 @@ function hook_node_type_delete($info) {
  * removed from the node table in the database, before hook_node_delete() is
  * invoked, and before field_attach_delete() is called.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node that is being deleted.
  *
  * @ingroup node_api_hooks
  */
-function hook_delete(Drupal\node\Node $node) {
+function hook_delete(\Drupal\Core\Entity\EntityInterface $node) {
   db_delete('mytable')
     ->condition('nid', $node->nid)
     ->execute();
@@ -1108,12 +1108,12 @@ function hook_delete(Drupal\node\Node $node) {
  * This hook is invoked from NodeFormController::prepareEntity() before the
  * general hook_node_prepare() is invoked.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node that is about to be shown on the add/edit form.
  *
  * @ingroup node_api_hooks
  */
-function hook_prepare(Drupal\node\Node $node) {
+function hook_prepare(\Drupal\Core\Entity\EntityInterface $node) {
   if ($file = file_check_upload($field_name)) {
     $file = file_save_upload($field_name, _image_filename($file->filename, NULL, TRUE));
     if ($file) {
@@ -1144,7 +1144,7 @@ function hook_prepare(Drupal\node\Node $node) {
  * displayed automatically by the node module. This hook just needs to
  * return the node title and form editing fields specific to the node type.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node being added or edited.
  * @param $form_state
  *   The form state array.
@@ -1155,7 +1155,7 @@ function hook_prepare(Drupal\node\Node $node) {
  *
  * @ingroup node_api_hooks
  */
-function hook_form(Drupal\node\Node $node, &$form_state) {
+function hook_form(\Drupal\Core\Entity\EntityInterface $node, &$form_state) {
   $type = node_type_load($node->type);
 
   $form['title'] = array(
@@ -1196,12 +1196,12 @@ function hook_form(Drupal\node\Node $node, &$form_state) {
  * node table in the database, before field_attach_insert() is called, and
  * before hook_node_insert() is invoked.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node that is being created.
  *
  * @ingroup node_api_hooks
  */
-function hook_insert(Drupal\node\Node $node) {
+function hook_insert(\Drupal\Core\Entity\EntityInterface $node) {
   db_insert('mytable')
     ->fields(array(
       'nid' => $node->nid,
@@ -1255,12 +1255,12 @@ function hook_load($nodes) {
  * node table in the database, before field_attach_update() is called, and
  * before hook_node_update() is invoked.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node that is being updated.
  *
  * @ingroup node_api_hooks
  */
-function hook_update(Drupal\node\Node $node) {
+function hook_update(\Drupal\Core\Entity\EntityInterface $node) {
   db_update('mytable')
     ->fields(array('extra' => $node->extra))
     ->condition('nid', $node->nid)
@@ -1284,7 +1284,7 @@ function hook_update(Drupal\node\Node $node) {
  * have no effect.  The preferred method to change a node's content is to use
  * hook_node_presave() instead.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node being validated.
  * @param $form
  *   The form being used to edit the node.
@@ -1293,7 +1293,7 @@ function hook_update(Drupal\node\Node $node) {
  *
  * @ingroup node_api_hooks
  */
-function hook_validate(Drupal\node\Node $node, $form, &$form_state) {
+function hook_validate(\Drupal\Core\Entity\EntityInterface $node, $form, &$form_state) {
   if (isset($node->end) && isset($node->start)) {
     if ($node->start > $node->end) {
       form_set_error('time', t('An event may not end before it starts.'));
@@ -1311,7 +1311,7 @@ function hook_validate(Drupal\node\Node $node, $form, &$form_state) {
  * that the node type module can define a custom method for display, or add to
  * the default display.
  *
- * @param \Drupal\node\Plugin\Core\Entity\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node to be displayed, as returned by node_load().
  * @param \Drupal\entity\Plugin\Core\Entity\EntityDisplay $display
  *   The entity_display object holding the display options configured for the
@@ -1332,7 +1332,7 @@ function hook_validate(Drupal\node\Node $node, $form, &$form_state) {
  *
  * @ingroup node_api_hooks
  */
-function hook_view(\Drupal\node\Plugin\Core\Entity\Node $node, \Drupal\entity\Plugin\Core\Entity\EntityDisplay $display, $view_mode) {
+function hook_view(\Drupal\Core\Entity\EntityInterface $node, \Drupal\entity\Plugin\Core\Entity\EntityDisplay $display, $view_mode) {
   if ($view_mode == 'full' && node_is_page($node)) {
     $breadcrumb = array();
     $breadcrumb[] = l(t('Home'), NULL);
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 8019ff3..3f64e83 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -15,11 +15,10 @@
 use Drupal\Core\Database\Query\SelectExtender;
 use Drupal\Core\Database\Query\SelectInterface;
 use Drupal\Core\Datetime\DrupalDateTime;
-use Drupal\Core\Template\Attribute;
-use Drupal\node\Plugin\Core\Entity\Node;
-use Drupal\file\Plugin\Core\Entity\File;
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Template\Attribute;
 use Drupal\entity\Plugin\Core\Entity\EntityDisplay;
+use Drupal\file\Plugin\Core\Entity\File;
 
 /**
  * Denotes that the node is not published.
@@ -255,15 +254,15 @@ function node_entity_display_alter(EntityDisplay $display, $context) {
 /**
  * Entity URI callback.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   A node entity.
  *
  * @return array
  *   An array with 'path' as the key and the path to the node as its value.
  */
-function node_uri(Node $node) {
+function node_uri(EntityInterface $node) {
   return array(
-    'path' => 'node/' . $node->nid,
+    'path' => 'node/' . $node->nid->value,
   );
 }
 
@@ -412,13 +411,13 @@ function node_type_get_label($name) {
 /**
  * Returns the node type label for the passed node.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   A node entity to return the node type's label for.
  *
  * @return string|false
  *   The node type label or FALSE if the node type is not found.
  */
-function node_get_type_label($node) {
+function node_get_type_label(EntityInterface $node) {
   $types = _node_types_build()->names;
   return isset($types[$node->type]) ? $types[$node->type] : FALSE;
 }
@@ -911,7 +910,7 @@ function node_hook($type, $hook) {
 /**
  * Invokes a node hook.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   A Node entity.
  * @param $hook
  *   A string containing the name of the hook.
@@ -922,7 +921,7 @@ function node_hook($type, $hook) {
  * @return
  *   The returned value of the invoked hook.
  */
-function node_invoke($node, $hook, $a2 = NULL, $a3 = NULL, $a4 = NULL) {
+function node_invoke(EntityInterface $node, $hook, $a2 = NULL, $a3 = NULL, $a4 = NULL) {
   if ($function = node_hook($node->type, $hook)) {
     return $function($node, $a2, $a3, $a4);
   }
@@ -948,7 +947,12 @@ function node_invoke($node, $hook, $a2 = NULL, $a3 = NULL, $a4 = NULL) {
  * @see Drupal\Core\Entity\Query\EntityQueryInterface
  */
 function node_load_multiple(array $nids = NULL, $reset = FALSE) {
-  return entity_load_multiple('node', $nids, $reset);
+  $entities = entity_load_multiple('node', $nids, $reset);
+  // Return BC-entities.
+  foreach ($entities as $id => $entity) {
+    $entities[$id] = $entity->getBCEntity();
+  }
+  return $entities;
 }
 
 /**
@@ -964,7 +968,8 @@ function node_load_multiple(array $nids = NULL, $reset = FALSE) {
  *   A fully-populated node entity, or FALSE if the node is not found.
  */
 function node_load($nid = NULL, $reset = FALSE) {
-  return entity_load('node', $nid, $reset);
+  $entity = entity_load('node', $nid, $reset);
+  return $entity ? $entity->getBCEntity() : FALSE;
 }
 
 /**
@@ -983,13 +988,13 @@ function node_revision_load($vid = NULL) {
 /**
  * Prepares a node for saving by populating the author and creation date.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   A node object.
  *
  * @return Drupal\node\Node
  *   An updated node object.
  */
-function node_submit(Node $node) {
+function node_submit(EntityInterface $node) {
   global $user;
 
   // A user might assign the node author by entering a user name in the node
@@ -1017,11 +1022,11 @@ function node_submit(Node $node) {
 /**
  * Saves changes to a node or adds a new node.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The $node entity to be saved. If $node->nid is
  *   omitted (or $node->is_new is TRUE), a new node will be added.
  */
-function node_save(Node $node) {
+function node_save(EntityInterface $node) {
   $node->save();
 }
 
@@ -1064,7 +1069,7 @@ function node_revision_delete($revision_id) {
 /**
  * Page callback: Generates an array which displays a node detail page.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   A node entity.
  * @param $message
  *   (optional) A flag which sets a page title relevant to the revision being
@@ -1075,7 +1080,7 @@ function node_revision_delete($revision_id) {
  *
  * @see node_menu()
  */
-function node_show(Node $node, $message = FALSE) {
+function node_show(EntityInterface $node, $message = FALSE) {
   if ($message) {
     drupal_set_title(t('Revision of %title from %date', array('%title' => $node->label(), '%date' => format_date($node->revision_timestamp))), PASS_THROUGH);
   }
@@ -1094,13 +1099,13 @@ function node_show(Node $node, $message = FALSE) {
 /**
  * Checks whether the current page is the full page view of the passed-in node.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   A node entity.
  *
  * @return
  *   The ID of the node if this is a full page view, otherwise FALSE.
  */
-function node_is_page(Node $node) {
+function node_is_page(EntityInterface $node) {
   $page_node = menu_get_object();
   return (!empty($page_node) ? $page_node->nid == $node->nid : FALSE);
 }
@@ -1408,7 +1413,7 @@ function node_search_execute($keys = NULL, $conditions = NULL) {
       'type' => check_plain(node_get_type_label($node)),
       'title' => $node->label($item->langcode),
       'user' => theme('username', array('account' => $node)),
-      'date' => $node->get('changed', $item->langcode),
+      'date' => $node->changed,
       'node' => $node,
       'extra' => $extra,
       'score' => $item->calculated_score,
@@ -1539,7 +1544,7 @@ function theme_node_search_admin($variables) {
 /**
  * Access callback: Checks node revision access.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node to check.
  * @param $op
  *   (optional) The specific operation being checked. Defaults to 'view.'
@@ -1557,7 +1562,7 @@ function theme_node_search_admin($variables) {
  *
  * @see node_menu()
  */
-function _node_revision_access(Node $node, $op = 'view', $account = NULL, $langcode = NULL) {
+function _node_revision_access(EntityInterface $node, $op = 'view', $account = NULL, $langcode = NULL) {
   $access = &drupal_static(__FUNCTION__, array());
 
   $map = array(
@@ -1846,7 +1851,7 @@ function node_type_page_title($type) {
 /**
  * Title callback: Displays the node's title.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node entity.
  *
  * @return
@@ -1854,7 +1859,7 @@ function node_type_page_title($type) {
  *
  * @see node_menu()
  */
-function node_page_title(Node $node) {
+function node_page_title(EntityInterface $node) {
   return $node->label();
 }
 
@@ -1874,13 +1879,13 @@ function node_last_changed($nid) {
 /**
  * Returns a list of all the existing revision numbers for the node passed in.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node entity.
  *
  * @return
  *   An associative array keyed by node revision number.
  */
-function node_revision_list(Node $node) {
+function node_revision_list(EntityInterface $node) {
   $revisions = array();
   $result = db_query('SELECT r.vid, r.title, r.log, r.uid, n.vid AS current_vid, r.timestamp, u.name FROM {node_revision} r LEFT JOIN {node} n ON n.vid = r.vid INNER JOIN {users} u ON u.uid = r.uid WHERE r.nid = :nid ORDER BY r.vid DESC', array(':nid' => $node->nid));
   foreach ($result as $revision) {
@@ -2155,7 +2160,7 @@ function node_feed($nids = FALSE, $channel = array()) {
 /**
  * Generates an array for rendering the given node.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   A node entity.
  * @param $view_mode
  *   (optional) View mode, e.g., 'full', 'teaser'... Defaults to 'full.'
@@ -2166,7 +2171,7 @@ function node_feed($nids = FALSE, $channel = array()) {
  * @return
  *   An array as expected by drupal_render().
  */
-function node_view(Node $node, $view_mode = 'full', $langcode = NULL) {
+function node_view(EntityInterface $node, $view_mode = 'full', $langcode = NULL) {
   return entity_view($node, $view_mode, $langcode);
 }
 
@@ -2247,7 +2252,7 @@ function node_page_default() {
 /**
  * Page callback: Displays a single node.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node entity.
  *
  * @return
@@ -2255,7 +2260,7 @@ function node_page_default() {
  *
  * @see node_menu()
  */
-function node_page_view(Node $node) {
+function node_page_view(EntityInterface $node) {
   // If there is a menu link to this node, the link becomes the last part
   // of the active trail, and the link name becomes the page title.
   // Thus, we must explicitly set the page title to be the node title.
@@ -2296,10 +2301,10 @@ function node_update_index() {
 /**
  * Indexes a single node.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node to index.
  */
-function _node_index_node(Node $node) {
+function _node_index_node(EntityInterface $node) {
 
   // Save the changed time of the most recent indexed node, for the search
   // results half-life calculation.
@@ -2555,7 +2560,7 @@ function node_form_system_themes_admin_form_submit($form, &$form_state) {
  *   - "update"
  *   - "delete"
  *   - "create"
- * @param Drupal\node\Node|string|stdClass $node
+ * @param Drupal\Core\Entity\EntityInterface|string|stdClass $node
  *   The node entity on which the operation is to be performed, or the node type
  *   object, or node type string (e.g., 'forum') for the 'create' operation.
  * @param $account
@@ -2631,7 +2636,7 @@ function node_access($op, $node, $account = NULL, $langcode = NULL) {
   }
 
   // Check if authors can view their own unpublished nodes.
-  if ($op == 'view' && !$node->get('status', $langcode) && user_access('view own unpublished content', $account) && $account->uid == $node->get('uid', $langcode) && $account->uid != 0) {
+  if ($op == 'view' && empty($node->get('status', $langcode)->value) && user_access('view own unpublished content', $account) && $account->uid == $node->get('uid', $langcode)->value && $account->uid != 0) {
     $rights[$account->uid][$cid][$langcode][$op] = TRUE;
     return TRUE;
   }
@@ -2668,7 +2673,7 @@ function node_access($op, $node, $account = NULL, $langcode = NULL) {
       $rights[$account->uid][$cid][$langcode][$op] = $result;
       return $result;
     }
-    elseif (is_object($node) && $op == 'view' && $node->get('status', $langcode)) {
+    elseif (is_object($node) && $op == 'view' && !empty($node->get('status', $langcode)->value)) {
       // If no modules implement hook_node_grants(), the default behavior is to
       // allow all users to view published nodes, so reflect that here.
       $rights[$account->uid][$cid][$langcode][$op] = TRUE;
@@ -2982,13 +2987,13 @@ function node_query_node_access_alter(AlterableInterface $query) {
  * via hook_node_access_records_alter() implementations, and saves the collected
  * and altered grants to the database.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The $node to acquire grants for.
  * @param $delete
  *   (optional) Whether to delete existing node access records before inserting
  *   new ones. Defaults to TRUE.
  */
-function node_access_acquire_grants(Node $node, $delete = TRUE) {
+function node_access_acquire_grants(EntityInterface $node, $delete = TRUE) {
   $grants = module_invoke_all('node_access_records', $node);
   // Let modules alter the grants.
   drupal_alter('node_access_records', $grants, $node);
@@ -3010,7 +3015,7 @@ function node_access_acquire_grants(Node $node, $delete = TRUE) {
  * Note: Don't call this function directly from a contributed module. Call
  * node_access_acquire_grants() instead.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node whose grants are being written.
  * @param $grants
  *   A list of grants to write. Each grant is an array that must contain the
@@ -3028,7 +3033,7 @@ function node_access_acquire_grants(Node $node, $delete = TRUE) {
  *
  * @see node_access_acquire_grants()
  */
-function _node_access_write_grants(Node $node, $grants, $realm = NULL, $delete = TRUE) {
+function _node_access_write_grants(EntityInterface $node, $grants, $realm = NULL, $delete = TRUE) {
   if ($delete) {
     $query = db_delete('node_access')->condition('nid', $node->nid);
     if ($realm) {
@@ -3231,7 +3236,7 @@ function _node_access_rebuild_batch_finished($success, $results, $operations) {
 /**
  * Implements hook_form().
  */
-function node_content_form(Node $node, $form_state) {
+function node_content_form(EntityInterface $node, $form_state) {
   // @todo It is impossible to define a content type without implementing
   //   hook_form(). Remove this requirement.
   $form = array();
@@ -3327,7 +3332,7 @@ function node_action_info() {
 /**
  * Sets the status of a node to 1 (published).
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   A node entity.
  * @param $context
  *   (optional) Array of additional information about what triggered the action.
@@ -3335,7 +3340,7 @@ function node_action_info() {
  *
  * @ingroup actions
  */
-function node_publish_action(Node $node, $context = array()) {
+function node_publish_action(EntityInterface $node, $context = array()) {
   $node->status = NODE_PUBLISHED;
   watchdog('action', 'Set @type %title to published.', array('@type' => node_get_type_label($node), '%title' => $node->label()));
 }
@@ -3343,7 +3348,7 @@ function node_publish_action(Node $node, $context = array()) {
 /**
  * Sets the status of a node to 0 (unpublished).
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   A node entity.
  * @param $context
  *   (optional) Array of additional information about what triggered the action.
@@ -3351,7 +3356,7 @@ function node_publish_action(Node $node, $context = array()) {
  *
  * @ingroup actions
  */
-function node_unpublish_action(Node $node, $context = array()) {
+function node_unpublish_action(EntityInterface $node, $context = array()) {
   $node->status = NODE_NOT_PUBLISHED;
   watchdog('action', 'Set @type %title to unpublished.', array('@type' => node_get_type_label($node), '%title' => $node->label()));
 }
@@ -3359,7 +3364,7 @@ function node_unpublish_action(Node $node, $context = array()) {
 /**
  * Sets the sticky-at-top-of-list property of a node to 1.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   A node entity.
  * @param $context
  *   (optional) Array of additional information about what triggered the action.
@@ -3367,7 +3372,7 @@ function node_unpublish_action(Node $node, $context = array()) {
  *
  * @ingroup actions
  */
-function node_make_sticky_action(Node $node, $context = array()) {
+function node_make_sticky_action(EntityInterface $node, $context = array()) {
   $node->sticky = NODE_STICKY;
   watchdog('action', 'Set @type %title to sticky.', array('@type' => node_get_type_label($node), '%title' => $node->label()));
 }
@@ -3375,7 +3380,7 @@ function node_make_sticky_action(Node $node, $context = array()) {
 /**
  * Sets the sticky-at-top-of-list property of a node to 0.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   A node entity.
  * @param $context
  *   (optional) Array of additional information about what triggered the action.
@@ -3383,7 +3388,7 @@ function node_make_sticky_action(Node $node, $context = array()) {
  *
  * @ingroup actions
  */
-function node_make_unsticky_action(Node $node, $context = array()) {
+function node_make_unsticky_action(EntityInterface $node, $context = array()) {
   $node->sticky = NODE_NOT_STICKY;
   watchdog('action', 'Set @type %title to unsticky.', array('@type' => node_get_type_label($node), '%title' => $node->label()));
 }
@@ -3391,7 +3396,7 @@ function node_make_unsticky_action(Node $node, $context = array()) {
 /**
  * Sets the promote property of a node to 1.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   A node entity.
  * @param $context
  *   (optional) Array of additional information about what triggered the action.
@@ -3399,7 +3404,7 @@ function node_make_unsticky_action(Node $node, $context = array()) {
  *
  * @ingroup actions
  */
-function node_promote_action(Node $node, $context = array()) {
+function node_promote_action(EntityInterface $node, $context = array()) {
   $node->promote = NODE_PROMOTED;
   watchdog('action', 'Promoted @type %title to front page.', array('@type' => node_get_type_label($node), '%title' => $node->label()));
 }
@@ -3407,7 +3412,7 @@ function node_promote_action(Node $node, $context = array()) {
 /**
  * Sets the promote property of a node to 0.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   A node entity.
  * @param $context
  *   (optional) Array of additional information about what triggered the action.
@@ -3415,7 +3420,7 @@ function node_promote_action(Node $node, $context = array()) {
  *
  * @ingroup actions
  */
-function node_unpromote_action(Node $node, $context = array()) {
+function node_unpromote_action(EntityInterface $node, $context = array()) {
   $node->promote = NODE_NOT_PROMOTED;
   watchdog('action', 'Removed @type %title from front page.', array('@type' => node_get_type_label($node), '%title' => $node->label()));
 }
@@ -3423,12 +3428,12 @@ function node_unpromote_action(Node $node, $context = array()) {
 /**
  * Saves a node.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node to be saved.
  *
  * @ingroup actions
  */
-function node_save_action(Node $node) {
+function node_save_action(EntityInterface $node) {
   $node->save();
   watchdog('action', 'Saved @type %title', array('@type' => node_get_type_label($node), '%title' => $node->label()));
 }
@@ -3436,7 +3441,7 @@ function node_save_action(Node $node) {
 /**
  * Assigns ownership of a node to a user.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   A node entity to modify.
  * @param $context
  *   Array of additional information about what triggered the action. Includes
@@ -3448,7 +3453,7 @@ function node_save_action(Node $node) {
  * @see node_assign_owner_action_submit()
  * @ingroup actions
  */
-function node_assign_owner_action(Node $node, $context) {
+function node_assign_owner_action(EntityInterface $node, $context) {
   $node->uid = $context['owner_uid'];
   $owner_name = db_query("SELECT name FROM {users} WHERE uid = :uid", array(':uid' => $context['owner_uid']))->fetchField();
   watchdog('action', 'Changed owner of @type %title to uid %name.', array('@type' =>  node_get_type_label($node), '%title' => $node->label(), '%name' => $owner_name));
@@ -3557,7 +3562,7 @@ function node_unpublish_by_keyword_action_submit($form, $form_state) {
 /**
  * Unpublishes a node containing certain keywords.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   A node entity to modify.
  * @param $context
  *   Array of additional information about what triggered the action. Includes
@@ -3570,7 +3575,7 @@ function node_unpublish_by_keyword_action_submit($form, $form_state) {
  *
  * @ingroup actions
  */
-function node_unpublish_by_keyword_action(Node $node, $context) {
+function node_unpublish_by_keyword_action(EntityInterface $node, $context) {
   foreach ($context['keywords'] as $keyword) {
     $elements = node_view(clone $node);
     if (strpos(drupal_render($elements), $keyword) !== FALSE || strpos($node->label(), $keyword) !== FALSE) {
diff --git a/core/modules/node/node.pages.inc b/core/modules/node/node.pages.inc
index 008ef76..863babd 100644
--- a/core/modules/node/node.pages.inc
+++ b/core/modules/node/node.pages.inc
@@ -9,7 +9,7 @@
  * @see node_menu()
  */
 
-use Drupal\node\Plugin\Core\Entity\Node;
+use Drupal\Core\Entity\EntityInterface;
 
 /**
  * Page callback: Presents the node editing form.
@@ -106,7 +106,7 @@ function node_add($node_type) {
     'name' => (isset($user->name) ? $user->name : ''),
     'type' => $type,
     'langcode' => $langcode ? $langcode : language_default()->langcode,
-  ));
+  ))->getBCEntity();
   drupal_set_title(t('Create @name', array('@name' => $node_type->name)), PASS_THROUGH);
   $output = entity_get_form($node);
 
@@ -116,7 +116,7 @@ function node_add($node_type) {
 /**
  * Generates a node preview.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node to preview.
  *
  * @return
@@ -124,7 +124,7 @@ function node_add($node_type) {
  *
  * @see node_form_build_preview()
  */
-function node_preview(Node $node) {
+function node_preview(EntityInterface $node) {
   if (node_access('create', $node) || node_access('update', $node)) {
     _field_invoke_multiple('load', 'node', array($node->nid => $node));
     // Load the user's name when needed.
diff --git a/core/modules/node/tests/modules/node_access_test/node_access_test.module b/core/modules/node/tests/modules/node_access_test/node_access_test.module
index 4efee88..deaf9bb 100644
--- a/core/modules/node/tests/modules/node_access_test/node_access_test.module
+++ b/core/modules/node/tests/modules/node_access_test/node_access_test.module
@@ -9,7 +9,7 @@
  * a special 'node test view' permission.
  */
 
-use Drupal\node\Plugin\Core\Entity\Node;
+use Drupal\Core\Entity\EntityInterface;
 
 /**
  * Implements hook_node_grants().
@@ -32,7 +32,7 @@ function node_access_test_node_grants($account, $op) {
 /**
  * Implements hook_node_access_records().
  */
-function node_access_test_node_access_records(Node $node) {
+function node_access_test_node_access_records(EntityInterface $node) {
   $grants = array();
   // For NodeAccessBaseTableTestCase, only set records for private nodes.
   if (!state()->get('node_access_test.private') || $node->private) {
@@ -207,28 +207,28 @@ function node_access_test_node_load($nodes, $types) {
  * Implements hook_node_predelete().
  */
 
-function node_access_test_node_predelete(Node $node) {
+function node_access_test_node_predelete(EntityInterface $node) {
   db_delete('node_access_test')->condition('nid', $node->nid)->execute();
 }
 
 /**
  * Implements hook_node_insert().
  */
-function node_access_test_node_insert(Node $node) {
+function node_access_test_node_insert(EntityInterface $node) {
   _node_access_test_node_write($node);
 }
 
 /**
  * Implements hook_nodeapi_update().
  */
-function node_access_test_node_update(Node $node) {
+function node_access_test_node_update(EntityInterface $node) {
   _node_access_test_node_write($node);
 }
 
 /**
  * Helper for node insert/update.
  */
-function _node_access_test_node_write(Node $node) {
+function _node_access_test_node_write(EntityInterface $node) {
   if (isset($node->private)) {
     db_merge('node_access_test')
       ->key(array('nid' => $node->nid))
diff --git a/core/modules/node/tests/modules/node_test/node_test.module b/core/modules/node/tests/modules/node_test/node_test.module
index 36b59c9..467af62 100644
--- a/core/modules/node/tests/modules/node_test/node_test.module
+++ b/core/modules/node/tests/modules/node_test/node_test.module
@@ -8,7 +8,7 @@
  * interaction with the Node module.
  */
 
-use Drupal\node\Plugin\Core\Entity\Node;
+use Drupal\Core\Entity\EntityInterface;
 use Drupal\entity\Plugin\Core\Entity\EntityDisplay;
 
 /**
@@ -30,7 +30,7 @@ function node_test_node_load($nodes, $types) {
 /**
  * Implements hook_node_view().
  */
-function node_test_node_view(Node $node, EntityDisplay $display, $view_mode) {
+function node_test_node_view(EntityInterface $node, EntityDisplay $display, $view_mode) {
   if ($view_mode == 'rss') {
     // Add RSS elements and namespaces when building the RSS feed.
     $node->rss_elements[] = array(
@@ -71,7 +71,7 @@ function node_test_node_grants($account, $op) {
 /**
  * Implements hook_node_access_records().
  */
-function node_test_node_access_records(Node $node) {
+function node_test_node_access_records(EntityInterface $node) {
   // Return nothing when testing for empty responses.
   if (!empty($node->disable_node_access)) {
     return;
@@ -105,7 +105,7 @@ function node_test_node_access_records(Node $node) {
 /**
  * Implements hook_node_access_records_alter().
  */
-function node_test_node_access_records_alter(&$grants, Node $node) {
+function node_test_node_access_records_alter(&$grants, EntityInterface $node) {
   if (!empty($grants)) {
     foreach ($grants as $key => $grant) {
       // Alter grant from test_page_realm to test_alter_realm and modify the gid.
@@ -128,7 +128,7 @@ function node_test_node_grants_alter(&$grants, $account, $op) {
 /**
  * Implements hook_node_presave().
  */
-function node_test_node_presave(Node $node) {
+function node_test_node_presave(EntityInterface $node) {
   if ($node->title == 'testing_node_presave') {
     // Sun, 19 Nov 1978 05:00:00 GMT
     $node->created = 280299600;
@@ -146,7 +146,7 @@ function node_test_node_presave(Node $node) {
 /**
  * Implements hook_node_update().
  */
-function node_test_node_update(Node $node) {
+function node_test_node_update(EntityInterface $node) {
   // Determine changes on update.
   if (!empty($node->original) && $node->original->title == 'test_changes') {
     if ($node->original->title != $node->title) {
@@ -172,7 +172,7 @@ function node_test_entity_view_mode_alter(&$view_mode, Drupal\Core\Entity\Entity
  *
  * @see \Drupal\node\Tests\NodeSaveTest::testNodeSaveOnInsert()
  */
-function node_test_node_insert(Node $node) {
+function node_test_node_insert(EntityInterface $node) {
   // Set the node title to the node ID and save.
   if ($node->title == 'new') {
     $node->title = 'Node '. $node->nid;
diff --git a/core/modules/node/tests/modules/node_test_exception/node_test_exception.module b/core/modules/node/tests/modules/node_test_exception/node_test_exception.module
index 359af1f..9eaa4f1 100644
--- a/core/modules/node/tests/modules/node_test_exception/node_test_exception.module
+++ b/core/modules/node/tests/modules/node_test_exception/node_test_exception.module
@@ -5,12 +5,12 @@
  * A module implementing node related hooks to test API interaction.
  */
 
-use Drupal\node\Plugin\Core\Entity\Node;
+use Drupal\Core\Entity\EntityInterface;
 
 /**
  * Implements hook_node_insert().
  */
-function node_test_exception_node_insert(Node $node) {
+function node_test_exception_node_insert(EntityInterface $node) {
   if ($node->title == 'testing_transaction_exception') {
     throw new Exception('Test exception for rollback.');
   }
diff --git a/core/modules/number/lib/Drupal/number/Tests/NumberFieldTest.php b/core/modules/number/lib/Drupal/number/Tests/NumberFieldTest.php
index 925828c..9ee7a0f 100644
--- a/core/modules/number/lib/Drupal/number/Tests/NumberFieldTest.php
+++ b/core/modules/number/lib/Drupal/number/Tests/NumberFieldTest.php
@@ -19,7 +19,7 @@ class NumberFieldTest extends WebTestBase {
    *
    * @var array
    */
-  public static $modules = array('node', 'field_test', 'number', 'field_ui');
+  public static $modules = array('node', 'entity_test', 'number', 'field_ui');
 
   protected $field;
   protected $instance;
@@ -36,7 +36,7 @@ public static function getInfo() {
   function setUp() {
     parent::setUp();
 
-    $this->web_user = $this->drupalCreateUser(array('access field_test content', 'administer field_test content', 'administer content types', 'administer node fields','administer node display'));
+    $this->web_user = $this->drupalCreateUser(array('view test entity', 'administer entity_test content', 'administer content types', 'administer node fields','administer node display'));
     $this->drupalLogin($this->web_user);
   }
 
@@ -55,8 +55,8 @@ function testNumberDecimalField() {
     field_create_field($this->field);
     $this->instance = array(
       'field_name' => $this->field['field_name'],
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle',
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
       'widget' => array(
         'type' => 'number',
         'settings' => array(
@@ -70,12 +70,12 @@ function testNumberDecimalField() {
       ),
     );
     field_create_instance($this->instance);
-    entity_get_display('test_entity', 'test_bundle', 'default')
+    entity_get_display('entity_test', 'entity_test', 'default')
       ->setComponent($this->field['field_name'])
       ->save();
 
     // Display creation form.
-    $this->drupalGet('test-entity/add/test_bundle');
+    $this->drupalGet('entity_test/add');
     $langcode = LANGUAGE_NOT_SPECIFIED;
     $this->assertFieldByName("{$this->field['field_name']}[$langcode][0][value]", '', 'Widget is displayed');
     $this->assertRaw('placeholder="0.00"');
@@ -83,12 +83,14 @@ function testNumberDecimalField() {
     // Submit a signed decimal value within the allowed precision and scale.
     $value = '-1234.5678';
     $edit = array(
+      'user_id' => 1,
+      'name' => $this->randomName(),
       "{$this->field['field_name']}[$langcode][0][value]" => $value,
     );
     $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
+    preg_match('|entity_test/manage/(\d+)/edit|', $this->url, $match);
     $id = $match[1];
-    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created');
+    $this->assertText(t('entity_test @id has been created.', array('@id' => $id)), 'Entity was created');
     $this->assertRaw(round($value, 2), 'Value is displayed.');
 
     // Try to create entries with more than one decimal separator; assert fail.
@@ -101,7 +103,7 @@ function testNumberDecimalField() {
     );
 
     foreach ($wrong_entries as $wrong_entry) {
-      $this->drupalGet('test-entity/add/test_bundle');
+      $this->drupalGet('entity_test/add');
       $edit = array(
         "{$this->field['field_name']}[$langcode][0][value]" => $wrong_entry,
       );
@@ -119,7 +121,7 @@ function testNumberDecimalField() {
     );
 
     foreach ($wrong_entries as $wrong_entry) {
-      $this->drupalGet('test-entity/add/test_bundle');
+      $this->drupalGet('entity_test/add');
       $edit = array(
         "{$this->field['field_name']}[$langcode][0][value]" => $wrong_entry,
       );
diff --git a/core/modules/options/lib/Drupal/options/Tests/OptionsDynamicValuesTest.php b/core/modules/options/lib/Drupal/options/Tests/OptionsDynamicValuesTest.php
index 4065b7d..34da251 100644
--- a/core/modules/options/lib/Drupal/options/Tests/OptionsDynamicValuesTest.php
+++ b/core/modules/options/lib/Drupal/options/Tests/OptionsDynamicValuesTest.php
@@ -19,7 +19,14 @@ class OptionsDynamicValuesTest extends FieldTestBase {
    *
    * @var array
    */
-  public static $modules = array('options', 'field_test', 'options_test');
+  public static $modules = array('options', 'entity_test', 'options_test');
+
+  /**
+   * The created entity.
+   *
+   * @var \Drupal\Core\Entity\Entity
+   */
+  protected $entity;
 
   function setUp() {
     parent::setUp();
@@ -37,22 +44,28 @@ function setUp() {
 
     $this->instance = array(
       'field_name' => $this->field_name,
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle',
+      'entity_type' => 'entity_test_rev',
+      'bundle' => 'entity_test_rev',
       'required' => TRUE,
       'widget' => array(
         'type' => 'options_select',
       ),
     );
     $this->instance = field_create_instance($this->instance);
+    // Create an entity and prepare test data that will be used by
+    // options_test_dynamic_values_callback().
+    $values = array(
+      'user_id' => mt_rand(1, 10),
+      'name' => $this->randomName(),
+    );
+    $this->entity = entity_create('entity_test_rev', $values);
+    $this->entity->save();
+    $uri = $this->entity->uri();
     $this->test = array(
-      'id' => mt_rand(1, 10),
-      // Make sure this does not equal the ID so that
-      // options_test_dynamic_values_callback() always returns 4 values.
-      'vid' => mt_rand(20, 30),
-      'bundle' => 'test_bundle',
-      'label' => $this->randomName(),
+      'label' => $this->entity->label(),
+      'uuid' => $this->entity->uuid(),
+      'bundle' => $this->entity->bundle(),
+      'uri' => $uri['path'],
     );
-    $this->entity = call_user_func_array('field_test_create_entity', $this->test);
   }
 }
diff --git a/core/modules/options/lib/Drupal/options/Tests/OptionsDynamicValuesValidationTest.php b/core/modules/options/lib/Drupal/options/Tests/OptionsDynamicValuesValidationTest.php
index 693605a..374be4e 100644
--- a/core/modules/options/lib/Drupal/options/Tests/OptionsDynamicValuesValidationTest.php
+++ b/core/modules/options/lib/Drupal/options/Tests/OptionsDynamicValuesValidationTest.php
@@ -27,9 +27,9 @@ public static function getInfo() {
   function testDynamicAllowedValues() {
     // Verify that the test passes against every value we had.
     foreach ($this->test as $key => $value) {
-      $this->entity->test_options[LANGUAGE_NOT_SPECIFIED][0]['value'] = $value;
+      $this->entity->test_options->value = $value;
       try {
-        field_attach_validate($this->entity);
+        field_attach_validate($this->entity->getBCEntity());
         $this->pass("$key should pass");
       }
       catch (FieldValidationException $e) {
@@ -39,10 +39,10 @@ function testDynamicAllowedValues() {
     }
     // Now verify that the test does not pass against anything else.
     foreach ($this->test as $key => $value) {
-      $this->entity->test_options[LANGUAGE_NOT_SPECIFIED][0]['value'] = is_numeric($value) ? (100 - $value) : ('X' . $value);
+      $this->entity->test_options->value = is_numeric($value) ? (100 - $value) : ('X' . $value);
       $pass = FALSE;
       try {
-        field_attach_validate($this->entity);
+        field_attach_validate($this->entity->getBCEntity());
       }
       catch (FieldValidationException $e) {
         $pass = TRUE;
diff --git a/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUITest.php b/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUITest.php
index 3409185..5f6fcc1 100644
--- a/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUITest.php
+++ b/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUITest.php
@@ -70,7 +70,7 @@ function testOptionsAllowedValuesInteger() {
     // Create a node with actual data for the field.
     $settings = array(
       'type' => $this->type,
-      $this->field_name => array(LANGUAGE_NOT_SPECIFIED => array(array('value' => 1))),
+      $this->field_name =>array(array('value' => 1)),
     );
     $node = $this->drupalCreateNode($settings);
 
@@ -120,7 +120,7 @@ function testOptionsAllowedValuesFloat() {
     // Create a node with actual data for the field.
     $settings = array(
       'type' => $this->type,
-      $this->field_name => array(LANGUAGE_NOT_SPECIFIED => array(array('value' => .5))),
+      $this->field_name => array(array('value' => .5)),
     );
     $node = $this->drupalCreateNode($settings);
 
@@ -172,7 +172,7 @@ function testOptionsAllowedValuesText() {
     // Create a node with actual data for the field.
     $settings = array(
       'type' => $this->type,
-      $this->field_name => array(LANGUAGE_NOT_SPECIFIED => array(array('value' => 'One'))),
+      $this->field_name => array(array('value' => 'One')),
     );
     $node = $this->drupalCreateNode($settings);
 
diff --git a/core/modules/options/lib/Drupal/options/Tests/OptionsSelectDynamicValuesTest.php b/core/modules/options/lib/Drupal/options/Tests/OptionsSelectDynamicValuesTest.php
index 4344d21..0237546 100644
--- a/core/modules/options/lib/Drupal/options/Tests/OptionsSelectDynamicValuesTest.php
+++ b/core/modules/options/lib/Drupal/options/Tests/OptionsSelectDynamicValuesTest.php
@@ -27,11 +27,11 @@ function testSelectListDynamic() {
     $this->entity->save();
 
     // Create a web user.
-    $web_user = $this->drupalCreateUser(array('access field_test content', 'administer field_test content'));
+    $web_user = $this->drupalCreateUser(array('view test entity', 'administer entity_test content'));
     $this->drupalLogin($web_user);
 
     // Display form.
-    $this->drupalGet('test-entity/manage/' . $this->entity->ftid . '/edit');
+    $this->drupalGet('entity_test_rev/manage/' . $this->entity->id() . '/edit');
     $options = $this->xpath('//select[@id="edit-test-options-und"]/option');
     $this->assertEqual(count($options), count($this->test) + 1);
     foreach ($options as $option) {
diff --git a/core/modules/options/lib/Drupal/options/Tests/OptionsWidgetsTest.php b/core/modules/options/lib/Drupal/options/Tests/OptionsWidgetsTest.php
index 023f012..d07626a 100644
--- a/core/modules/options/lib/Drupal/options/Tests/OptionsWidgetsTest.php
+++ b/core/modules/options/lib/Drupal/options/Tests/OptionsWidgetsTest.php
@@ -19,7 +19,7 @@ class OptionsWidgetsTest extends FieldTestBase {
    *
    * @var array
    */
-  public static $modules = array('options', 'field_test', 'options_test', 'taxonomy', 'field_ui');
+  public static $modules = array('options', 'entity_test', 'options_test', 'taxonomy', 'field_ui');
 
   public static function getInfo() {
     return array(
@@ -69,7 +69,7 @@ function setUp() {
     $this->bool = field_create_field($this->bool);
 
     // Create a web user.
-    $this->web_user = $this->drupalCreateUser(array('access field_test content', 'administer field_test content'));
+    $this->web_user = $this->drupalCreateUser(array('view test entity', 'administer entity_test content'));
     $this->drupalLogin($this->web_user);
   }
 
@@ -80,8 +80,8 @@ function testRadioButtons() {
     // Create an instance of the 'single value' field.
     $instance = array(
       'field_name' => $this->card_1['field_name'],
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle',
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
       'widget' => array(
         'type' => 'options_buttons',
       ),
@@ -90,13 +90,15 @@ function testRadioButtons() {
     $langcode = LANGUAGE_NOT_SPECIFIED;
 
     // Create an entity.
-    $entity_init = field_test_create_entity();
-    $entity = clone $entity_init;
-    $entity->is_new = TRUE;
-    field_test_entity_save($entity);
+    $entity = entity_create('entity_test', array(
+      'user_id' => 1,
+      'name' => $this->randomName(),
+    ));
+    $entity->save();
+    $entity_init = clone $entity;
 
     // With no field data, no buttons are checked.
-    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
+    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
     $this->assertNoFieldChecked("edit-card-1-$langcode-0");
     $this->assertNoFieldChecked("edit-card-1-$langcode-1");
     $this->assertNoFieldChecked("edit-card-1-$langcode-2");
@@ -108,7 +110,7 @@ function testRadioButtons() {
     $this->assertFieldValues($entity_init, 'card_1', $langcode, array(0));
 
     // Check that the selected button is checked.
-    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
+    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
     $this->assertFieldChecked("edit-card-1-$langcode-0");
     $this->assertNoFieldChecked("edit-card-1-$langcode-1");
     $this->assertNoFieldChecked("edit-card-1-$langcode-2");
@@ -123,7 +125,7 @@ function testRadioButtons() {
     field_update_field($this->card_1);
     $instance['required'] = TRUE;
     field_update_instance($instance);
-    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
+    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
     $this->assertFieldChecked("edit-card-1-$langcode-99");
   }
 
@@ -134,8 +136,8 @@ function testCheckBoxes() {
     // Create an instance of the 'multiple values' field.
     $instance = array(
       'field_name' => $this->card_2['field_name'],
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle',
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
       'widget' => array(
         'type' => 'options_buttons',
       ),
@@ -144,13 +146,15 @@ function testCheckBoxes() {
     $langcode = LANGUAGE_NOT_SPECIFIED;
 
     // Create an entity.
-    $entity_init = field_test_create_entity();
-    $entity = clone $entity_init;
-    $entity->is_new = TRUE;
-    field_test_entity_save($entity);
+    $entity = entity_create('entity_test', array(
+      'user_id' => 1,
+      'name' => $this->randomName(),
+    ));
+    $entity->save();
+    $entity_init = clone $entity;
 
     // Display form: with no field data, nothing is checked.
-    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
+    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
     $this->assertNoFieldChecked("edit-card-2-$langcode-0");
     $this->assertNoFieldChecked("edit-card-2-$langcode-1");
     $this->assertNoFieldChecked("edit-card-2-$langcode-2");
@@ -166,7 +170,7 @@ function testCheckBoxes() {
     $this->assertFieldValues($entity_init, 'card_2', $langcode, array(0, 2));
 
     // Display form: check that the right options are selected.
-    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
+    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
     $this->assertFieldChecked("edit-card-2-$langcode-0");
     $this->assertNoFieldChecked("edit-card-2-$langcode-1");
     $this->assertFieldChecked("edit-card-2-$langcode-2");
@@ -181,7 +185,7 @@ function testCheckBoxes() {
     $this->assertFieldValues($entity_init, 'card_2', $langcode, array(0));
 
     // Display form: check that the right options are selected.
-    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
+    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
     $this->assertFieldChecked("edit-card-2-$langcode-0");
     $this->assertNoFieldChecked("edit-card-2-$langcode-1");
     $this->assertNoFieldChecked("edit-card-2-$langcode-2");
@@ -210,7 +214,7 @@ function testCheckBoxes() {
     field_update_field($this->card_2);
     $instance['required'] = TRUE;
     field_update_instance($instance);
-    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
+    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
     $this->assertFieldChecked("edit-card-2-$langcode-99");
   }
 
@@ -221,8 +225,8 @@ function testSelectListSingle() {
     // Create an instance of the 'single value' field.
     $instance = array(
       'field_name' => $this->card_1['field_name'],
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle',
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
       'required' => TRUE,
       'widget' => array(
         'type' => 'options_select',
@@ -232,13 +236,15 @@ function testSelectListSingle() {
     $langcode = LANGUAGE_NOT_SPECIFIED;
 
     // Create an entity.
-    $entity_init = field_test_create_entity();
-    $entity = clone $entity_init;
-    $entity->is_new = TRUE;
-    field_test_entity_save($entity);
+    $entity = entity_create('entity_test', array(
+      'user_id' => 1,
+      'name' => $this->randomName(),
+    ));
+    $entity->save();
+    $entity_init = clone $entity;
 
     // Display form.
-    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
+    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
     // A required field without any value has a "none" option.
     $this->assertTrue($this->xpath('//select[@id=:id]//option[@value="_none" and text()=:label]', array(':id' => 'edit-card-1-' . $langcode, ':label' => t('- Select a value -'))), 'A required select list has a "Select a value" choice.');
 
@@ -260,7 +266,7 @@ function testSelectListSingle() {
     $this->assertFieldValues($entity_init, 'card_1', $langcode, array(0));
 
     // Display form: check that the right options are selected.
-    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
+    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
     // A required field with a value has no 'none' option.
     $this->assertFalse($this->xpath('//select[@id=:id]//option[@value="_none"]', array(':id' => 'edit-card-1-' . $langcode)), 'A required select list with an actual value has no "none" choice.');
     $this->assertOptionSelected("edit-card-1-$langcode", 0);
@@ -272,12 +278,12 @@ function testSelectListSingle() {
     field_update_instance($instance);
 
     // Display form.
-    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
+    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
     // A non-required field has a 'none' option.
     $this->assertTrue($this->xpath('//select[@id=:id]//option[@value="_none" and text()=:label]', array(':id' => 'edit-card-1-' . $langcode, ':label' => t('- None -'))), 'A non-required select list has a "None" choice.');
     // Submit form: Unselect the option.
     $edit = array("card_1[$langcode]" => '_none');
-    $this->drupalPost('test-entity/manage/' . $entity->ftid . '/edit', $edit, t('Save'));
+    $this->drupalPost('entity_test/manage/' . $entity->id() . '/edit', $edit, t('Save'));
     $this->assertFieldValues($entity_init, 'card_1', $langcode, array());
 
     // Test optgroups.
@@ -287,7 +293,7 @@ function testSelectListSingle() {
     field_update_field($this->card_1);
 
     // Display form: with no field data, nothing is selected
-    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
+    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
     $this->assertNoOptionSelected("edit-card-1-$langcode", 0);
     $this->assertNoOptionSelected("edit-card-1-$langcode", 1);
     $this->assertNoOptionSelected("edit-card-1-$langcode", 2);
@@ -300,14 +306,14 @@ function testSelectListSingle() {
     $this->assertFieldValues($entity_init, 'card_1', $langcode, array(0));
 
     // Display form: check that the right options are selected.
-    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
+    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
     $this->assertOptionSelected("edit-card-1-$langcode", 0);
     $this->assertNoOptionSelected("edit-card-1-$langcode", 1);
     $this->assertNoOptionSelected("edit-card-1-$langcode", 2);
 
     // Submit form: Unselect the option.
     $edit = array("card_1[$langcode]" => '_none');
-    $this->drupalPost('test-entity/manage/' . $entity->ftid . '/edit', $edit, t('Save'));
+    $this->drupalPost('entity_test/manage/' . $entity->id() . '/edit', $edit, t('Save'));
     $this->assertFieldValues($entity_init, 'card_1', $langcode, array());
   }
 
@@ -318,8 +324,8 @@ function testSelectListMultiple() {
     // Create an instance of the 'multiple values' field.
     $instance = array(
       'field_name' => $this->card_2['field_name'],
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle',
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
       'widget' => array(
         'type' => 'options_select',
       ),
@@ -328,13 +334,15 @@ function testSelectListMultiple() {
     $langcode = LANGUAGE_NOT_SPECIFIED;
 
     // Create an entity.
-    $entity_init = field_test_create_entity();
-    $entity = clone $entity_init;
-    $entity->is_new = TRUE;
-    field_test_entity_save($entity);
+    $entity = entity_create('entity_test', array(
+      'user_id' => 1,
+      'name' => $this->randomName(),
+    ));
+    $entity->save();
+    $entity_init = clone $entity;
 
     // Display form: with no field data, nothing is selected.
-    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
+    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
     $this->assertNoOptionSelected("edit-card-2-$langcode", 0);
     $this->assertNoOptionSelected("edit-card-2-$langcode", 1);
     $this->assertNoOptionSelected("edit-card-2-$langcode", 2);
@@ -346,7 +354,7 @@ function testSelectListMultiple() {
     $this->assertFieldValues($entity_init, 'card_2', $langcode, array(0, 2));
 
     // Display form: check that the right options are selected.
-    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
+    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
     $this->assertOptionSelected("edit-card-2-$langcode", 0);
     $this->assertNoOptionSelected("edit-card-2-$langcode", 1);
     $this->assertOptionSelected("edit-card-2-$langcode", 2);
@@ -357,7 +365,7 @@ function testSelectListMultiple() {
     $this->assertFieldValues($entity_init, 'card_2', $langcode, array(0));
 
     // Display form: check that the right options are selected.
-    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
+    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
     $this->assertOptionSelected("edit-card-2-$langcode", 0);
     $this->assertNoOptionSelected("edit-card-2-$langcode", 1);
     $this->assertNoOptionSelected("edit-card-2-$langcode", 2);
@@ -377,18 +385,18 @@ function testSelectListMultiple() {
     // Check that the 'none' option has no efect if actual options are selected
     // as well.
     $edit = array("card_2[$langcode][]" => array('_none' => '_none', 0 => 0));
-    $this->drupalPost('test-entity/manage/' . $entity->ftid . '/edit', $edit, t('Save'));
+    $this->drupalPost('entity_test/manage/' . $entity->id() . '/edit', $edit, t('Save'));
     $this->assertFieldValues($entity_init, 'card_2', $langcode, array(0));
 
     // Check that selecting the 'none' option empties the field.
     $edit = array("card_2[$langcode][]" => array('_none' => '_none'));
-    $this->drupalPost('test-entity/manage/' . $entity->ftid . '/edit', $edit, t('Save'));
+    $this->drupalPost('entity_test/manage/' . $entity->id() . '/edit', $edit, t('Save'));
     $this->assertFieldValues($entity_init, 'card_2', $langcode, array());
 
     // A required select list does not have an empty key.
     $instance['required'] = TRUE;
     field_update_instance($instance);
-    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
+    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
     $this->assertFalse($this->xpath('//select[@id=:id]//option[@value=""]', array(':id' => 'edit-card-2-' . $langcode)), 'A required select list does not have an empty key.');
 
     // We do not have to test that a required select list with one option is
@@ -404,7 +412,7 @@ function testSelectListMultiple() {
     field_update_instance($instance);
 
     // Display form: with no field data, nothing is selected.
-    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
+    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
     $this->assertNoOptionSelected("edit-card-2-$langcode", 0);
     $this->assertNoOptionSelected("edit-card-2-$langcode", 1);
     $this->assertNoOptionSelected("edit-card-2-$langcode", 2);
@@ -417,14 +425,14 @@ function testSelectListMultiple() {
     $this->assertFieldValues($entity_init, 'card_2', $langcode, array(0));
 
     // Display form: check that the right options are selected.
-    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
+    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
     $this->assertOptionSelected("edit-card-2-$langcode", 0);
     $this->assertNoOptionSelected("edit-card-2-$langcode", 1);
     $this->assertNoOptionSelected("edit-card-2-$langcode", 2);
 
     // Submit form: Unselect the option.
     $edit = array("card_2[$langcode][]" => array('_none' => '_none'));
-    $this->drupalPost('test-entity/manage/' . $entity->ftid . '/edit', $edit, t('Save'));
+    $this->drupalPost('entity_test/manage/' . $entity->id() . '/edit', $edit, t('Save'));
     $this->assertFieldValues($entity_init, 'card_2', $langcode, array());
   }
 
@@ -435,8 +443,8 @@ function testOnOffCheckbox() {
     // Create an instance of the 'boolean' field.
     $instance = array(
       'field_name' => $this->bool['field_name'],
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle',
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
       'widget' => array(
         'type' => 'options_onoff',
       ),
@@ -445,13 +453,15 @@ function testOnOffCheckbox() {
     $langcode = LANGUAGE_NOT_SPECIFIED;
 
     // Create an entity.
-    $entity_init = field_test_create_entity();
-    $entity = clone $entity_init;
-    $entity->is_new = TRUE;
-    field_test_entity_save($entity);
+    $entity = entity_create('entity_test', array(
+      'user_id' => 1,
+      'name' => $this->randomName(),
+    ));
+    $entity->save();
+    $entity_init = clone $entity;
 
     // Display form: with no field data, option is unchecked.
-    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
+    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
     $this->assertNoFieldChecked("edit-bool-$langcode");
     $this->assertRaw('Some dangerous &amp; unescaped <strong>markup</strong>', 'Option text was properly filtered.');
 
@@ -461,7 +471,7 @@ function testOnOffCheckbox() {
     $this->assertFieldValues($entity_init, 'bool', $langcode, array(0));
 
     // Display form: check that the right options are selected.
-    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
+    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
     $this->assertFieldChecked("edit-bool-$langcode");
 
     // Submit form: uncheck the option.
@@ -470,7 +480,7 @@ function testOnOffCheckbox() {
     $this->assertFieldValues($entity_init, 'bool', $langcode, array(1));
 
     // Display form: with 'off' value, option is unchecked.
-    $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
+    $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
     $this->assertNoFieldChecked("edit-bool-$langcode");
 
     // Create Basic page node type.
diff --git a/core/modules/options/tests/options_test.module b/core/modules/options/tests/options_test.module
index 90f6bf1..4ece85c 100644
--- a/core/modules/options/tests/options_test.module
+++ b/core/modules/options/tests/options_test.module
@@ -30,10 +30,11 @@ function options_test_allowed_values_callback($field, $instance, $entity) {
 function options_test_dynamic_values_callback($field, $instance, EntityInterface $entity, &$cacheable) {
   $cacheable = FALSE;
   // We need the values of the entity as keys.
+  $uri = $entity->uri();
   return drupal_map_assoc(array(
-    $entity->ftlabel,
-    $entity->id(),
-    $entity->getRevisionId(),
+    $entity->label(),
+    $uri['path'],
+    $entity->uuid(),
     $entity->bundle(),
   ));
 }
diff --git a/core/modules/path/path.module b/core/modules/path/path.module
index 6401a8b..b6a38f6 100644
--- a/core/modules/path/path.module
+++ b/core/modules/path/path.module
@@ -5,7 +5,7 @@
  * Enables users to rename URLs.
  */
 
-use Drupal\node\Plugin\Core\Entity\Node;
+use Drupal\Core\Entity\EntityInterface;
 
 use Drupal\taxonomy\Plugin\Core\Entity\Term;
 
@@ -186,7 +186,7 @@ function path_form_element_validate($element, &$form_state, $complete_form) {
 /**
  * Implements hook_node_insert().
  */
-function path_node_insert(Node $node) {
+function path_node_insert(EntityInterface $node) {
   if (isset($node->path)) {
     $alias = trim($node->path['alias']);
     // Only save a non-empty alias.
@@ -202,7 +202,7 @@ function path_node_insert(Node $node) {
 /**
  * Implements hook_node_update().
  */
-function path_node_update(Node $node) {
+function path_node_update(EntityInterface $node) {
   if (isset($node->path)) {
     $path = $node->path;
     $alias = trim($path['alias']);
@@ -223,7 +223,7 @@ function path_node_update(Node $node) {
 /**
  * Implements hook_node_predelete().
  */
-function path_node_predelete(Node $node) {
+function path_node_predelete(EntityInterface $node) {
   // Delete all aliases associated with this node.
   drupal_container()->get('path.crud')->delete(array('source' => 'node/' . $node->nid));
 }
diff --git a/core/modules/php/lib/Drupal/php/Tests/PhpTestBase.php b/core/modules/php/lib/Drupal/php/Tests/PhpTestBase.php
index 596ebd8..abb3412 100644
--- a/core/modules/php/lib/Drupal/php/Tests/PhpTestBase.php
+++ b/core/modules/php/lib/Drupal/php/Tests/PhpTestBase.php
@@ -58,6 +58,6 @@ function setUp() {
    * @return stdObject Node object.
    */
   function createNodeWithCode() {
-    return $this->drupalCreateNode(array('body' => array(LANGUAGE_NOT_SPECIFIED => array(array('value' => '<?php print "SimpleTest PHP was executed!"; ?>')))));
+    return $this->drupalCreateNode(array('body' => array(array('value' => '<?php print "SimpleTest PHP was executed!"; ?>'))));
   }
 }
diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/CrudTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/CrudTest.php
index 3383f94..0b5c29a 100644
--- a/core/modules/rdf/lib/Drupal/rdf/Tests/CrudTest.php
+++ b/core/modules/rdf/lib/Drupal/rdf/Tests/CrudTest.php
@@ -34,7 +34,7 @@ public static function getInfo() {
    */
   function testCRUD() {
     // Verify loading of a default mapping.
-    $mapping = _rdf_mapping_load('test_entity', 'test_bundle');
+    $mapping = _rdf_mapping_load('entity_test', 'entity_test');
     $this->assertTrue(count($mapping), 'Default mapping was found.');
 
     // Verify saving a mapping.
diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/MappingHookTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/MappingHookTest.php
index eb1340e..b05f4af 100644
--- a/core/modules/rdf/lib/Drupal/rdf/Tests/MappingHookTest.php
+++ b/core/modules/rdf/lib/Drupal/rdf/Tests/MappingHookTest.php
@@ -19,7 +19,7 @@ class MappingHookTest extends WebTestBase {
    *
    * @var array
    */
-  public static $modules = array('rdf', 'rdf_test', 'field_test');
+  public static $modules = array('rdf', 'rdf_test', 'entity_test');
 
   public static function getInfo() {
     return array(
@@ -34,7 +34,7 @@ public static function getInfo() {
    */
   function testMapping() {
     // Test that the mapping is returned correctly by the hook.
-    $mapping = rdf_mapping_load('test_entity', 'test_bundle');
+    $mapping = rdf_mapping_load('entity_test', 'entity_test');
     $this->assertIdentical($mapping['rdftype'], array('sioc:Post'), 'Mapping for rdftype is sioc:Post.');
     $this->assertIdentical($mapping['title'], array('predicates' => array('dc:title')), 'Mapping for title is dc:title.');
     $this->assertIdentical($mapping['created'], array(
@@ -44,7 +44,7 @@ function testMapping() {
     ), 'Mapping for created is dc:created with datatype xsd:dateTime and callback date_iso8601.');
     $this->assertIdentical($mapping['uid'], array('predicates' => array('sioc:has_creator', 'dc:creator'), 'type' => 'rel'), 'Mapping for uid is sioc:has_creator and dc:creator, and type is rel.');
 
-    $mapping = rdf_mapping_load('test_entity', 'test_bundle_no_mapping');
+    $mapping = rdf_mapping_load('entity_test', 'test_bundle_no_mapping');
     $this->assertEqual($mapping, array(), 'Empty array returned when an entity type, bundle pair has no mapping.');
   }
 }
diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/RdfaMarkupTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/RdfaMarkupTest.php
index 6f99dae..2fff526 100644
--- a/core/modules/rdf/lib/Drupal/rdf/Tests/RdfaMarkupTest.php
+++ b/core/modules/rdf/lib/Drupal/rdf/Tests/RdfaMarkupTest.php
@@ -19,7 +19,7 @@ class RdfaMarkupTest extends WebTestBase {
    *
    * @var array
    */
-  public static $modules = array('rdf', 'field_test', 'rdf_test');
+  public static $modules = array('rdf', 'entity_test', 'rdf_test');
 
   protected $profile = 'standard';
 
@@ -39,7 +39,7 @@ function testDrupalRdfaAttributes() {
     $expected_attributes = array(
       'property' => array('dc:title'),
     );
-    $mapping = rdf_mapping_load('test_entity', 'test_bundle');
+    $mapping = rdf_mapping_load('entity_test', 'entity_test');
     $attributes = rdf_rdfa_attributes($mapping['title']);
     ksort($expected_attributes);
     ksort($attributes);
@@ -53,7 +53,7 @@ function testDrupalRdfaAttributes() {
       'property' => array('dc:created'),
       'content' => $isoDate,
     );
-    $mapping = rdf_mapping_load('test_entity', 'test_bundle');
+    $mapping = rdf_mapping_load('entity_test', 'entity_test');
     $attributes = rdf_rdfa_attributes($mapping['created'], $date);
     ksort($expected_attributes);
     ksort($attributes);
@@ -64,7 +64,7 @@ function testDrupalRdfaAttributes() {
       'datatype' => 'foo:bar1type',
       'property' => array('foo:bar1'),
     );
-    $mapping = rdf_mapping_load('test_entity', 'test_bundle');
+    $mapping = rdf_mapping_load('entity_test', 'entity_test');
     $attributes = rdf_rdfa_attributes($mapping['foobar1']);
     ksort($expected_attributes);
     ksort($attributes);
@@ -74,7 +74,7 @@ function testDrupalRdfaAttributes() {
     $expected_attributes = array(
       'rel' => array('sioc:has_creator', 'dc:creator'),
     );
-    $mapping = rdf_mapping_load('test_entity', 'test_bundle');
+    $mapping = rdf_mapping_load('entity_test', 'entity_test');
     $attributes = rdf_rdfa_attributes($mapping['foobar_objproperty1']);
     ksort($expected_attributes);
     ksort($attributes);
@@ -84,7 +84,7 @@ function testDrupalRdfaAttributes() {
     $expected_attributes = array(
       'rev' => array('sioc:reply_of'),
     );
-    $mapping = rdf_mapping_load('test_entity', 'test_bundle');
+    $mapping = rdf_mapping_load('entity_test', 'entity_test');
     $attributes = rdf_rdfa_attributes($mapping['foobar_objproperty2']);
     ksort($expected_attributes);
     ksort($attributes);
diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/TrackerAttributesTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/TrackerAttributesTest.php
index 45488bd..b78cabd 100644
--- a/core/modules/rdf/lib/Drupal/rdf/Tests/TrackerAttributesTest.php
+++ b/core/modules/rdf/lib/Drupal/rdf/Tests/TrackerAttributesTest.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\rdf\Tests;
 
-use Drupal\node\Plugin\Core\Entity\Node;
+use Drupal\Core\Entity\EntityInterface;
 use Drupal\simpletest\WebTestBase;
 
 /**
@@ -71,10 +71,10 @@ function testAttributesInTracker() {
    *
    * Tests the tracker page for RDFa markup.
    *
-   * @param Node $node
+   * @param \Drupal\Core\Entity\EntityInterface $node
    * The node just created.
    */
-  function _testBasicTrackerRdfaMarkup(Node $node) {
+  function _testBasicTrackerRdfaMarkup(EntityInterface $node) {
     $node_uri = url('node/' . $node->nid, array('absolute' => TRUE));
     $user_uri = url('user/' . $node->uid, array('absolute' => TRUE));
 
diff --git a/core/modules/rdf/rdf.module b/core/modules/rdf/rdf.module
index 89494eb..547075a 100644
--- a/core/modules/rdf/rdf.module
+++ b/core/modules/rdf/rdf.module
@@ -787,9 +787,9 @@ function rdf_field_attach_view_alter(&$output, $context) {
       foreach ($element['#items'] as $delta => $item) {
         // This function is invoked during entity preview when taxonomy term
         // reference items might contain free-tagging terms that do not exist
-        // yet and thus have no $item['taxonomy_term'].
-        if (isset($item['taxonomy_term'])) {
-          $term = $item['taxonomy_term'];
+        // yet and thus have no $item['entity'].
+        if (isset($item['entity'])) {
+          $term = $item['entity'];
           if (!empty($term->rdf_mapping['rdftype'])) {
             $element[$delta]['#options']['attributes']['typeof'] = $term->rdf_mapping['rdftype'];
           }
diff --git a/core/modules/rdf/tests/rdf_test.module b/core/modules/rdf/tests/rdf_test.module
index 4d90472..ea45e43 100644
--- a/core/modules/rdf/tests/rdf_test.module
+++ b/core/modules/rdf/tests/rdf_test.module
@@ -11,8 +11,8 @@
 function rdf_test_rdf_mapping() {
   return array(
     array(
-      'type' => 'test_entity',
-      'bundle' => 'test_bundle',
+      'type' => 'entity_test',
+      'bundle' => 'entity_test',
       'mapping' => array(
         'rdftype' => array('sioc:Post'),
         'title' => array(
diff --git a/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php b/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php
index c428c86..f854632 100644
--- a/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php
+++ b/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php
@@ -142,7 +142,7 @@ protected function entityValues($entity_type) {
           'field_test_text' => array(0 => array('value' => $this->randomString())),
         );
       case 'node':
-        return array('title' => $this->randomString());
+        return array('title' => $this->randomString(), 'type' => $this->randomString());
       case 'user':
         return array('name' => $this->randomName());
       default:
diff --git a/core/modules/search/lib/Drupal/search/Tests/SearchCommentCountToggleTest.php b/core/modules/search/lib/Drupal/search/Tests/SearchCommentCountToggleTest.php
index 338174d..a83fc09 100644
--- a/core/modules/search/lib/Drupal/search/Tests/SearchCommentCountToggleTest.php
+++ b/core/modules/search/lib/Drupal/search/Tests/SearchCommentCountToggleTest.php
@@ -47,7 +47,7 @@ function setUp() {
     $this->searching_user = $this->drupalCreateUser(array('search content', 'access content', 'access comments', 'skip comment approval'));
 
     // Create initial nodes.
-    $node_params = array('type' => 'article', 'body' => array(LANGUAGE_NOT_SPECIFIED => array(array('value' => 'SearchCommentToggleTestCase'))));
+    $node_params = array('type' => 'article', 'body' => array(array('value' => 'SearchCommentToggleTestCase')));
 
     $this->searchable_nodes['1 comment'] = $this->drupalCreateNode($node_params);
     $this->searchable_nodes['0 comments'] = $this->drupalCreateNode($node_params);
diff --git a/core/modules/search/lib/Drupal/search/Tests/SearchCommentTest.php b/core/modules/search/lib/Drupal/search/Tests/SearchCommentTest.php
index d6c25b1..72771a3 100644
--- a/core/modules/search/lib/Drupal/search/Tests/SearchCommentTest.php
+++ b/core/modules/search/lib/Drupal/search/Tests/SearchCommentTest.php
@@ -221,7 +221,7 @@ function testAddNewComment() {
     $settings = array(
       'type' => 'article',
       'title' => 'short title',
-      'body' => array(LANGUAGE_NOT_SPECIFIED => array(array('value' => 'short body text'))),
+      'body' => array(array('value' => 'short body text')),
     );
 
     $user = $this->drupalCreateUser(array('search content', 'create article content', 'access content'));
diff --git a/core/modules/search/lib/Drupal/search/Tests/SearchExactTest.php b/core/modules/search/lib/Drupal/search/Tests/SearchExactTest.php
index 7d3ba42..c52549f 100644
--- a/core/modules/search/lib/Drupal/search/Tests/SearchExactTest.php
+++ b/core/modules/search/lib/Drupal/search/Tests/SearchExactTest.php
@@ -32,12 +32,12 @@ function testExactQuery() {
     );
     // Create nodes with exact phrase.
     for ($i = 0; $i <= 17; $i++) {
-      $settings['body'] = array(LANGUAGE_NOT_SPECIFIED => array(array('value' => 'love pizza')));
+      $settings['body'] = array(array('value' => 'love pizza'));
       $this->drupalCreateNode($settings);
     }
     // Create nodes containing keywords.
     for ($i = 0; $i <= 17; $i++) {
-      $settings['body'] = array(LANGUAGE_NOT_SPECIFIED => array(array('value' => 'love cheesy pizza')));
+      $settings['body'] = array(array('value' => 'love cheesy pizza'));
       $this->drupalCreateNode($settings);
     }
 
diff --git a/core/modules/search/lib/Drupal/search/Tests/SearchMultilingualEntityTest.php b/core/modules/search/lib/Drupal/search/Tests/SearchMultilingualEntityTest.php
index e534971..e9526d8 100644
--- a/core/modules/search/lib/Drupal/search/Tests/SearchMultilingualEntityTest.php
+++ b/core/modules/search/lib/Drupal/search/Tests/SearchMultilingualEntityTest.php
@@ -57,33 +57,35 @@ function setUp() {
     $nodes = array(
       array(
         'type' => 'page',
-        'body' => array(
-          'en' => array(array('value' => $this->randomName(32), 'format' => $default_format)),
-        ),
+        'body' => array(array('value' => $this->randomName(32), 'format' => $default_format)),
         'langcode' => 'en',
       ),
       array(
         'type' => 'page',
-        'body' => array(
-          'en' => array(array('value' => $this->randomName(32), 'format' => $default_format)),
-          'hu' => array(array('value' => $this->randomName(32), 'format' => $default_format)),
-        ),
+        'body' => array(array('value' => $this->randomName(32), 'format' => $default_format)),
         'langcode' => 'en',
       ),
       array(
         'type' => 'page',
-        'body' => array(
-          'en' => array(array('value' => $this->randomName(32), 'format' => $default_format)),
-          'hu' => array(array('value' => $this->randomName(32), 'format' => $default_format)),
-          'sv' => array(array('value' => $this->randomName(32), 'format' => $default_format)),
-        ),
+        'body' => array(array('value' => $this->randomName(32), 'format' => $default_format)),
         'langcode' => 'en',
       ),
     );
     $this->searchable_nodes = array();
-    foreach ($nodes as $node) {
-      $this->searchable_nodes[] = $this->drupalCreateNode($node);
+    foreach ($nodes as $setting) {
+      $this->searchable_nodes[] = $this->drupalCreateNode($setting);
     }
+    // Add a single translation to the second node.
+    $translation = $this->searchable_nodes[1]->getTranslation('hu');
+    $translation->body->value = $this->randomName(32);
+    $this->searchable_nodes[1]->save();
+
+    // Add two translations to the third node.
+    $translation = $this->searchable_nodes[2]->getTranslation('hu');
+    $translation->body->value = $this->randomName(32);
+    $translation = $this->searchable_nodes[2]->getTranslation('sv');
+    $translation->body->value = $this->randomName(32);
+    $this->searchable_nodes[2]->save();
   }
 
   /**
diff --git a/core/modules/search/lib/Drupal/search/Tests/SearchNodeAccessTest.php b/core/modules/search/lib/Drupal/search/Tests/SearchNodeAccessTest.php
index 19c94cb..67706cf 100644
--- a/core/modules/search/lib/Drupal/search/Tests/SearchNodeAccessTest.php
+++ b/core/modules/search/lib/Drupal/search/Tests/SearchNodeAccessTest.php
@@ -42,7 +42,7 @@ function setUp() {
    * Tests that search returns results with punctuation in the search phrase.
    */
   function testPhraseSearchPunctuation() {
-    $node = $this->drupalCreateNode(array('body' => array(LANGUAGE_NOT_SPECIFIED => array(array('value' => "The bunny's ears were fluffy.")))));
+    $node = $this->drupalCreateNode(array('body' => array(array('value' => "The bunny's ears were fluffy."))));
 
     // Update the search index.
     module_invoke_all('update_index');
diff --git a/core/modules/search/lib/Drupal/search/Tests/SearchNumberMatchingTest.php b/core/modules/search/lib/Drupal/search/Tests/SearchNumberMatchingTest.php
index 540526b..1e3bf78 100644
--- a/core/modules/search/lib/Drupal/search/Tests/SearchNumberMatchingTest.php
+++ b/core/modules/search/lib/Drupal/search/Tests/SearchNumberMatchingTest.php
@@ -45,7 +45,7 @@ function setUp() {
 
     foreach ($this->numbers as $num) {
       $info = array(
-        'body' => array(LANGUAGE_NOT_SPECIFIED => array(array('value' => $num))),
+        'body' => array(array('value' => $num)),
         'type' => 'page',
         'language' => LANGUAGE_NOT_SPECIFIED,
       );
diff --git a/core/modules/search/lib/Drupal/search/Tests/SearchNumbersTest.php b/core/modules/search/lib/Drupal/search/Tests/SearchNumbersTest.php
index 7d1a463..6e81e5e 100644
--- a/core/modules/search/lib/Drupal/search/Tests/SearchNumbersTest.php
+++ b/core/modules/search/lib/Drupal/search/Tests/SearchNumbersTest.php
@@ -51,7 +51,7 @@ function setUp() {
 
     foreach ($this->numbers as $doc => $num) {
       $info = array(
-        'body' => array(LANGUAGE_NOT_SPECIFIED => array(array('value' => $num))),
+        'body' => array(array('value' => $num)),
         'type' => 'page',
         'language' => LANGUAGE_NOT_SPECIFIED,
         'title' => $doc . ' number',
diff --git a/core/modules/search/lib/Drupal/search/Tests/SearchPreprocessLangcodeTest.php b/core/modules/search/lib/Drupal/search/Tests/SearchPreprocessLangcodeTest.php
index c5d2451..a8c2e61 100644
--- a/core/modules/search/lib/Drupal/search/Tests/SearchPreprocessLangcodeTest.php
+++ b/core/modules/search/lib/Drupal/search/Tests/SearchPreprocessLangcodeTest.php
@@ -43,7 +43,7 @@ function setUp() {
    */
   function testPreprocessLangcode() {
     // Create a node.
-    $node = $this->drupalCreateNode(array('body' => array('en' => array(array())), 'langcode' => 'en'));
+    $node = $this->drupalCreateNode(array('body' => array(array()), 'langcode' => 'en'));
 
     // First update the index. This does the initial processing.
     node_update_index();
@@ -68,7 +68,7 @@ function testPreprocessStemming() {
     // Create a node.
     $node = $this->drupalCreateNode(array(
       'title' => 'we are testing',
-      'body' => array('en' => array(array())),
+      'body' => array(array()),
       'langcode' => 'en',
     ));
 
diff --git a/core/modules/search/lib/Drupal/search/Tests/SearchRankingTest.php b/core/modules/search/lib/Drupal/search/Tests/SearchRankingTest.php
index 4987b56..b029032 100644
--- a/core/modules/search/lib/Drupal/search/Tests/SearchRankingTest.php
+++ b/core/modules/search/lib/Drupal/search/Tests/SearchRankingTest.php
@@ -36,7 +36,7 @@ function testRankings() {
       $settings = array(
         'type' => 'page',
         'title' => 'Drupal rocks',
-        'body' => array(LANGUAGE_NOT_SPECIFIED => array(array('value' => "Drupal's search rocks"))),
+        'body' => array(array('value' => "Drupal's search rocks")),
       );
       foreach (array(0, 1) as $num) {
         if ($num == 1) {
@@ -46,7 +46,7 @@ function testRankings() {
               $settings[$node_rank] = 1;
               break;
             case 'relevance':
-              $settings['body'][LANGUAGE_NOT_SPECIFIED][0]['value'] .= " really rocks";
+              $settings['body'][0]['value'] .= " really rocks";
               break;
             case 'recent':
               $settings['created'] = REQUEST_TIME + 3600;
@@ -128,13 +128,13 @@ function testHTMLRankings() {
     foreach ($shuffled_tags as $tag) {
       switch ($tag) {
         case 'a':
-          $settings['body'] = array(LANGUAGE_NOT_SPECIFIED => array(array('value' => l('Drupal Rocks', 'node'), 'format' => 'full_html')));
+          $settings['body'] = array(array('value' => l('Drupal Rocks', 'node'), 'format' => 'full_html'));
           break;
         case 'notag':
-          $settings['body'] = array(LANGUAGE_NOT_SPECIFIED => array(array('value' => 'Drupal Rocks')));
+          $settings['body'] = array(array('value' => 'Drupal Rocks'));
           break;
         default:
-          $settings['body'] = array(LANGUAGE_NOT_SPECIFIED => array(array('value' => "<$tag>Drupal Rocks</$tag>", 'format' => 'full_html')));
+          $settings['body'] = array(array('value' => "<$tag>Drupal Rocks</$tag>", 'format' => 'full_html'));
           break;
       }
       $nodes[$tag] = $this->drupalCreateNode($settings);
@@ -167,7 +167,7 @@ function testHTMLRankings() {
     // Test tags with the same weight against the sorted tags.
     $unsorted_tags = array('u', 'b', 'i', 'strong', 'em');
     foreach ($unsorted_tags as $tag) {
-      $settings['body'] = array(LANGUAGE_NOT_SPECIFIED => array(array('value' => "<$tag>Drupal Rocks</$tag>", 'format' => 'full_html')));
+      $settings['body'] = array(array('value' => "<$tag>Drupal Rocks</$tag>", 'format' => 'full_html'));
       $node = $this->drupalCreateNode($settings);
 
       // Update the search index.
@@ -203,7 +203,7 @@ function testDoubleRankings() {
     $settings = array(
       'type' => 'page',
       'title' => 'Drupal rocks',
-      'body' => array(LANGUAGE_NOT_SPECIFIED => array(array('value' => "Drupal's search rocks"))),
+      'body' => array(array('value' => "Drupal's search rocks")),
       'sticky' => 1,
     );
 
diff --git a/core/modules/search/search.module b/core/modules/search/search.module
index 375c43f..85e58d3 100644
--- a/core/modules/search/search.module
+++ b/core/modules/search/search.module
@@ -5,7 +5,7 @@
  * Enables site-wide keyword searching.
  */
 
-use Drupal\node\Plugin\Core\Entity\Node;
+use Drupal\Core\Entity\EntityInterface;
 
 /**
  * Matches all 'N' Unicode character classes (numbers)
@@ -792,7 +792,7 @@ function search_touch_node($nid) {
 /**
  * Implements hook_node_update_index().
  */
-function search_node_update_index(Node $node) {
+function search_node_update_index(EntityInterface $node) {
   // Transplant links to a node into the target node.
   $result = db_query("SELECT caption FROM {search_node_links} WHERE nid = :nid", array(':nid' => $node->nid), array('target' => 'slave'));
   $output = array();
@@ -807,7 +807,7 @@ function search_node_update_index(Node $node) {
 /**
  * Implements hook_node_update().
  */
-function search_node_update(Node $node) {
+function search_node_update(EntityInterface $node) {
   // Reindex the node when it is updated. The node is automatically indexed
   // when it is added, simply by being added to the node table.
   search_touch_node($node->nid);
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
index dce2ceb..202afe0 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
@@ -172,7 +172,7 @@ function __construct($test_id = NULL) {
    * @param $reset
    *   (optional) Whether to reset the entity cache.
    *
-   * @return
+   * @return \Drupal\Core\Entity\EntityInterface
    *   A node entity matching $title.
    */
   function drupalGetNodeByTitle($title, $reset = FALSE) {
@@ -201,7 +201,7 @@ function drupalGetNodeByTitle($title, $reset = FALSE) {
    *   The following defaults are provided:
    *   - body: Random string using the default filter format:
    *     @code
-   *       $settings['body'][LANGUAGE_NOT_SPECIFIED][0] = array(
+   *       $settings['body'][0] = array(
    *         'value' => $this->randomName(32),
    *         'format' => filter_default_format(),
    *       );
@@ -214,10 +214,7 @@ function drupalGetNodeByTitle($title, $reset = FALSE) {
    *   - status: NODE_PUBLISHED.
    *   - sticky: NODE_NOT_STICKY.
    *   - type: 'page'.
-   *   - langcode: LANGUAGE_NOT_SPECIFIED. (If a 'langcode' key is provided in
-   *     the array, this language code will also be used for a randomly
-   *     generated body field for that language, and the body for
-   *     LANGUAGE_NOT_SPECIFIED will remain empty.)
+   *   - langcode: LANGUAGE_NOT_SPECIFIED.
    *   - uid: The currently logged in user, or the user running test.
    *   - revision: 1. (Backwards-compatible binary flag indicating whether a
    *     new revision should be created; use 1 to specify a new revision.)
@@ -228,7 +225,7 @@ function drupalGetNodeByTitle($title, $reset = FALSE) {
   protected function drupalCreateNode(array $settings = array()) {
     // Populate defaults array.
     $settings += array(
-      'body'      => array(LANGUAGE_NOT_SPECIFIED => array(array())),
+      'body'      => array(array()),
       'title'     => $this->randomName(8),
       'changed'   => REQUEST_TIME,
       'promote'   => NODE_NOT_PROMOTED,
@@ -265,14 +262,10 @@ protected function drupalCreateNode(array $settings = array()) {
     }
 
     // Merge body field value and format separately.
-    $body = array(
+    $settings['body'][0] += array(
       'value' => $this->randomName(32),
       'format' => filter_default_format(),
     );
-    if (empty($settings['body'][$settings['langcode']])) {
-      $settings['body'][$settings['langcode']][0] = array();
-    }
-    $settings['body'][$settings['langcode']][0] += $body;
 
     $node = entity_create('node', $settings);
     if (!empty($settings['revision'])) {
diff --git a/core/modules/statistics/statistics.module b/core/modules/statistics/statistics.module
index f6a9d48..758f8df 100644
--- a/core/modules/statistics/statistics.module
+++ b/core/modules/statistics/statistics.module
@@ -5,7 +5,7 @@
  * Logs and displays content statistics for a site.
  */
 
-use Drupal\node\Plugin\Core\Entity\Node;
+use Drupal\Core\Entity\EntityInterface;
 use Drupal\entity\Plugin\Core\Entity\EntityDisplay;
 
 /**
@@ -47,7 +47,7 @@ function statistics_permission() {
 /**
  * Implements hook_node_view().
  */
-function statistics_node_view(Node $node, EntityDisplay $display, $view_mode) {
+function statistics_node_view(EntityInterface $node, EntityDisplay $display, $view_mode) {
   if (!empty($node->nid) && $view_mode == 'full' && node_is_page($node) && empty($node->in_preview)) {
     $node->content['#attached']['library'][] = array('statistics', 'drupal.statistics');
     $settings = array('data' => array('nid' => $node->nid), 'url' => url(drupal_get_path('module', 'statistics') . '/statistics.php'));
@@ -199,7 +199,7 @@ function _statistics_format_item($title, $path) {
 /**
  * Implements hook_node_predelete().
  */
-function statistics_node_predelete(Node $node) {
+function statistics_node_predelete(EntityInterface $node) {
   // clean up statistics table when node is deleted
   db_delete('node_counter')
     ->condition('nid', $node->nid)
diff --git a/core/modules/system/lib/Drupal/system/Tests/Common/CascadingStylesheetsTest.php b/core/modules/system/lib/Drupal/system/Tests/Common/CascadingStylesheetsTest.php
index 30cf24e..5e107e3 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Common/CascadingStylesheetsTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Common/CascadingStylesheetsTest.php
@@ -134,11 +134,9 @@ function testRenderInlineFullPage() {
     $settings = array(
       'type' => 'page',
       'body' => array(
-        LANGUAGE_NOT_SPECIFIED => array(
-          array(
-            'value' => t('This tests the inline CSS!') . "<?php drupal_add_css('$css', 'inline'); ?>",
-            'format' => $php_format_id,
-          ),
+        array(
+          'value' => t('This tests the inline CSS!') . "<?php drupal_add_css('$css', 'inline'); ?>",
+          'format' => $php_format_id,
         ),
       ),
       'promote' => 1,
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityBCDecoratorTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityBCDecoratorTest.php
new file mode 100644
index 0000000..2541ba5
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityBCDecoratorTest.php
@@ -0,0 +1,78 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\system\Tests\Entity\EntityBCDecoratorTest.
+ */
+
+namespace Drupal\system\Tests\Entity;
+
+/**
+ * Tests Entity API base functionality.
+ *
+ * @todo: Remove once the EntityBCDecorator is removed.
+ */
+class EntityBCDecoratorTest extends EntityUnitBaseTest  {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('filter', 'text', 'node', 'comment');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Entity Backward Compatibility Decorator',
+      'description' => 'Tests the Entity Backward Compatibility Decorator',
+      'group' => 'Entity API',
+    );
+  }
+
+  public function setUp() {
+    parent::setUp();
+    $this->installSchema('user', array('users_roles', 'users_data', 'role_permission'));
+    $this->installSchema('node', array('node', 'node_revision', 'node_type', 'node_access'));
+    $this->installSchema('comment', array('comment', 'node_comment_statistics'));
+  }
+
+  /**
+   * Tests using the entity BC decorator with entity properties.
+   *
+   * @see \Drupal\Core\Entity\EntityBCDecorator
+   */
+  public function testBCDecorator() {
+    // Test using comment subject via the BC decorator.
+    $this->createUser();
+    $node = entity_create('node', array(
+      'type' => 'page',
+      'uid' => 1,
+    ));
+    $node->save();
+    $comment = entity_create('comment', array(
+      'nid' => $node->nid,
+      'subject' => 'old-value',
+    ));
+    $comment->save();
+    $bc_entity = $comment->getBCEntity();
+
+    // Test reading of a defined property.
+    $this->assertEqual($bc_entity->subject, 'old-value', 'Accessing entity property via BC decorator.');
+    // Test writing of a defined property via the decorator.
+    $bc_entity->subject = 'new';
+    $this->assertEqual($bc_entity->subject, 'new', 'Updated defined entity property via BC decorator.');
+    $this->assertEqual($comment->subject->value, 'new', 'Updated defined entity property  via BC decorator.');
+
+    // Test writing of a defined property.
+    $comment->subject->value = 'newer';
+    $this->assertEqual($bc_entity->subject, 'newer', 'Updated defined entity property  via default entity class.');
+    $this->assertEqual($comment->subject->value, 'newer', 'Updated defined entity property via default entity class.');
+
+    // Test handling of an undefined property.
+    $this->assertFalse(isset($bc_entity->foo), 'Checking if isset() on undefnied property.');
+    $bc_entity->foo = 'bar';
+    $this->assertEqual($bc_entity->foo, 'bar', 'Accessing undefined entity property via BC decorator.');
+    $this->assertEqual($comment->foo, 'bar', 'Accessing undefined entity property via default entity class.');
+    $this->assertTrue(isset($bc_entity->foo), 'Checking if isset() on undefnied property.');
+  }
+}
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryTest.php
index a2ece4a..e0ae1fd 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryTest.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\system\Tests\Entity;
 
+use Drupal\Core\Language\Language;
+
 /**
  * Tests the basic Entity API.
  */
@@ -17,7 +19,7 @@ class EntityQueryTest extends EntityUnitBaseTest {
    *
    * @var array
    */
-  public static $modules = array('field_test');
+  public static $modules = array('field_test', 'language');
 
   /**
    * @var array
@@ -53,7 +55,9 @@ public static function getInfo() {
 
   function setUp() {
     parent::setUp();
-    $this->installSchema('field_test', array('test_entity', 'test_entity_revision', 'test_entity_bundle'));
+    $this->installSchema('entity_test', array('entity_test_rev', 'entity_test_rev_revision'));
+    $this->installSchema('language', array('language'));
+    $this->installSchema('system', array('variable'));
     $figures = drupal_strtolower($this->randomName());
     $greetings = drupal_strtolower($this->randomName());
     foreach (array($figures => 'shape', $greetings => 'text') as $field_name => $field_type) {
@@ -71,11 +75,11 @@ function setUp() {
       do {
         $bundle = $this->randomName();
       } while ($bundles && strtolower($bundles[0]) >= strtolower($bundle));
-      field_test_create_bundle($bundle);
+      entity_test_create_bundle($bundle);
       foreach ($fields as $field) {
         $instance = array(
           'field_name' => $field['field_name'],
-          'entity_type' => 'test_entity',
+          'entity_type' => 'entity_test_rev',
           'bundle' => $bundle,
         );
         field_create_instance($instance);
@@ -102,24 +106,34 @@ function setUp() {
       'format' => 'format-pl'
     ));
     // Make these languages available to the greetings field.
+    $language = new Language(array(
+      'langcode' => 'tr',
+      'name' => $this->randomString(),
+    ));
+    language_save($language);
+    $language = new Language(array(
+      'langcode' => 'pl',
+      'name' => $this->randomString(),
+    ));
+    language_save($language);
     $field_langcodes = &drupal_static('field_available_languages');
-    $field_langcodes['test_entity'][$greetings] = array('tr', 'pl');
+    $field_langcodes['entity_test_rev'][$greetings] = array('tr', 'pl');
     // Calculate the cartesian product of the unit array by looking at the
     // bits of $i and add the unit at the bits that are 1. For example,
     // decimal 13 is binary 1101 so unit 3,2 and 0 will be added to the
     // entity.
     for ($i = 1; $i <= 15; $i++) {
-      $entity = entity_create('test_entity', array(
-        'ftid' => $i,
-        'ftvid' => $i,
-        'fttype' => $bundles[$i & 1],
+      $entity = entity_create('entity_test_rev', array(
+        'id' => $i,
+        'revision_id' => $i,
+        'type' => $bundles[$i & 1],
       ));
       $entity->enforceIsNew();
       $entity->setNewRevision();
       foreach (array_reverse(str_split(decbin($i))) as $key => $bit) {
         if ($bit) {
           $unit = $units[$key];
-          $entity->{$unit[0]}[$unit[1]][] = $unit[2];
+          $entity->getTranslation($unit[1])->{$unit[0]}->setValue($unit[2]);
         }
       }
       $entity->save();
@@ -135,19 +149,19 @@ function setUp() {
   function testEntityQuery() {
     $greetings = $this->greetings;
     $figures = $this->figures;
-    $this->queryResults = $this->factory->get('test_entity')
+    $this->queryResults = $this->factory->get('entity_test_rev')
       ->exists($greetings, 'tr')
       ->condition("$figures.color", 'red')
-      ->sort('ftid')
+      ->sort('id')
       ->execute();
     // As unit 0 was the red triangle and unit 2 was the turkish greeting,
     // bit 0 and bit 2 needs to be set.
     $this->assertResult(5, 7, 13, 15);
 
-    $query = $this->factory->get('test_entity', 'OR')
+    $query = $this->factory->get('entity_test_rev', 'OR')
       ->exists($greetings, 'tr')
       ->condition("$figures.color", 'red')
-      ->sort('ftid');
+      ->sort('id');
     $count_query = clone $query;
     $this->assertEqual(12, $count_query->count()->execute());
     $this->queryResults = $query->execute();
@@ -156,9 +170,9 @@ function testEntityQuery() {
     $this->assertResult(1, 3, 4, 5, 6, 7, 9, 11, 12, 13, 14, 15);
 
     // Test cloning of query conditions.
-    $query = $this->factory->get('test_entity')
+    $query = $this->factory->get('entity_test_rev')
       ->condition("$figures.color", 'red')
-      ->sort('ftid');
+      ->sort('id');
     $cloned_query = clone $query;
     $cloned_query
       ->condition("$figures.shape", 'circle');
@@ -169,95 +183,95 @@ function testEntityQuery() {
     $this->queryResults = $cloned_query->execute();
     $this->assertResult();
 
-    $query = $this->factory->get('test_entity');
+    $query = $this->factory->get('entity_test_rev');
     $group = $query->orConditionGroup()
       ->exists($greetings, 'tr')
       ->condition("$figures.color", 'red');
     $this->queryResults = $query
       ->condition($group)
       ->condition("$greetings.value", 'sie', 'STARTS_WITH')
-      ->sort('ftvid')
+      ->sort('revision_id')
       ->execute();
     // Bit 3 and (bit 0 or 2) -- the above 8 part of the above.
     $this->assertResult(9, 11, 12, 13, 14, 15);
 
     // No figure has both the colors blue and red at the same time.
-    $this->queryResults = $this->factory->get('test_entity')
+    $this->queryResults = $this->factory->get('entity_test_rev')
       ->condition("$figures.color", 'blue')
       ->condition("$figures.color", 'red')
-      ->sort('ftid')
+      ->sort('id')
       ->execute();
     $this->assertResult();
 
     // But an entity might have a red and a blue figure both.
-    $query = $this->factory->get('test_entity');
+    $query = $this->factory->get('entity_test_rev');
     $group_blue = $query->andConditionGroup()->condition("$figures.color", 'blue');
     $group_red = $query->andConditionGroup()->condition("$figures.color", 'red');
     $this->queryResults = $query
       ->condition($group_blue)
       ->condition($group_red)
-      ->sort('ftvid')
+      ->sort('revision_id')
       ->execute();
     // Unit 0 and unit 1, so bits 0 1.
     $this->assertResult(3, 7, 11, 15);
 
-    $this->queryResults = $this->factory->get('test_entity')
+    $this->queryResults = $this->factory->get('entity_test_rev')
       ->exists("$figures.color")
       ->notExists("$greetings.value")
-      ->sort('ftid')
+      ->sort('id')
       ->execute();
     // Bit 0 or 1 is on but 2 and 3 are not.
     $this->assertResult(1, 2, 3);
     // Now update the 'merhaba' string to xsiemax which is not a meaningful
     // word but allows us to test revisions and string operations.
-    $ids = $this->factory->get('test_entity')
+    $ids = $this->factory->get('entity_test_rev')
       ->condition("$greetings.value", 'merhaba')
       ->execute();
-    $entities = entity_load_multiple('test_entity', $ids);
+    $entities = entity_load_multiple('entity_test_rev', $ids);
     foreach ($entities as $entity) {
       $entity->setNewRevision();
-      $entity->{$greetings}['tr'][0]['value'] = 'xsiemax';
+      $entity->getTranslation('tr')->$greetings->value = 'xsiemax';
       $entity->save();
     }
     // When querying current revisions, this string is no longer found.
-    $this->queryResults = $this->factory->get('test_entity')
+    $this->queryResults = $this->factory->get('entity_test_rev')
       ->condition("$greetings.value", 'merhaba')
       ->execute();
     $this->assertResult();
-    $this->queryResults = $this->factory->get('test_entity')
+    $this->queryResults = $this->factory->get('entity_test_rev')
       ->condition("$greetings.value", 'merhaba')
       ->age(FIELD_LOAD_REVISION)
-      ->sort('ftvid')
+      ->sort('revision_id')
       ->execute();
     // Bit 2 needs to be set.
     // The keys must be 16-23 because the first batch stopped at 15 so the
     // second started at 16 and eight entities were saved.
     $assert = $this->assertRevisionResult(range(16, 23), array(4, 5, 6, 7, 12, 13, 14, 15));
-    $results = $this->factory->get('test_entity')
+    $results = $this->factory->get('entity_test_rev')
       ->condition("$greetings.value", 'siema', 'CONTAINS')
-      ->sort('ftid')
+      ->sort('id')
       ->execute();
     // This is the same as the previous one because xsiemax replaced merhaba
     // but also it contains the entities that siema originally but not
     // merhaba.
     $assert = array_slice($assert, 0, 4, TRUE) + array(8 => '8', 9 => '9', 10 => '10', 11 => '11') + array_slice($assert, 4, 4, TRUE);
     $this->assertIdentical($results, $assert);
-    $results = $this->factory->get('test_entity')
+    $results = $this->factory->get('entity_test_rev')
       ->condition("$greetings.value", 'siema', 'STARTS_WITH')
       ->execute();
     // Now we only get the ones that originally were siema, entity id 8 and
     // above.
     $this->assertIdentical($results, array_slice($assert, 4, 8, TRUE));
-    $results = $this->factory->get('test_entity')
+    $results = $this->factory->get('entity_test_rev')
       ->condition("$greetings.value", 'a', 'ENDS_WITH')
       ->execute();
     // It is very important that we do not get the ones which only have
     // xsiemax despite originally they were merhaba, ie. ended with a.
     $this->assertIdentical($results, array_slice($assert, 4, 8, TRUE));
-    $results = $this->factory->get('test_entity')
+    $results = $this->factory->get('entity_test_rev')
       ->condition("$greetings.value", 'a', 'ENDS_WITH')
       ->age(FIELD_LOAD_REVISION)
-      ->sort('ftid')
+      ->sort('id')
       ->execute();
     // Now we get everything.
     $this->assertIdentical($results, $assert);
@@ -272,18 +286,18 @@ function testSort() {
     $greetings = $this->greetings;
     $figures = $this->figures;
     // Order up and down on a number.
-    $this->queryResults = $this->factory->get('test_entity')
-      ->sort('ftid')
+    $this->queryResults = $this->factory->get('entity_test_rev')
+      ->sort('id')
       ->execute();
     $this->assertResult(range(1, 15));
-    $this->queryResults = $this->factory->get('test_entity')
-      ->sort('ftid', 'DESC')
+    $this->queryResults = $this->factory->get('entity_test_rev')
+      ->sort('id', 'DESC')
       ->execute();
     $this->assertResult(range(15, 1));
-    $query = $this->factory->get('test_entity')
+    $query = $this->factory->get('entity_test_rev')
       ->sort("$figures.color")
       ->sort("$greetings.format")
-      ->sort('ftid');
+      ->sort('id');
     // As we do not have any conditions, here are the possible colors and
     // language codes, already in order, with the first occurence of the
     // entity id marked with *:
@@ -326,19 +340,19 @@ function testSort() {
     // Test the pager by setting element #1 to page 2 with a page size of 4.
     // Results will be #8-12 from above.
     $_GET['page'] = '0,2';
-    $this->queryResults = $this->factory->get('test_entity')
+    $this->queryResults = $this->factory->get('entity_test_rev')
       ->sort("$figures.color")
       ->sort("$greetings.format")
-      ->sort('ftid')
+      ->sort('id')
       ->pager(4, 1)
       ->execute();
     $this->assertResult(15, 6, 7, 1);
 
     // Now test the reversed order.
-    $query = $this->factory->get('test_entity')
+    $query = $this->factory->get('entity_test_rev')
       ->sort("$figures.color", 'DESC')
       ->sort("$greetings.format", 'DESC')
-      ->sort('ftid', 'DESC');
+      ->sort('id', 'DESC');
     $count_query = clone $query;
     $this->assertEqual(15, $count_query->count()->execute());
     $this->queryResults = $query->execute();
@@ -355,26 +369,26 @@ protected function testTableSort() {
     $_GET['sort'] = 'asc';
     $_GET['order'] = 'Type';
     $header = array(
-      'id' => array('data' => 'Id', 'specifier' => 'ftid'),
+      'id' => array('data' => 'Id', 'specifier' => 'id'),
       'type' => array('data' => 'Type', 'specifier' => 'fttype'),
     );
 
-    $this->queryResults = array_values($this->factory->get('test_entity')
+    $this->queryResults = array_values($this->factory->get('entity_test_rev')
       ->tableSort($header)
       ->execute());
     $this->assertBundleOrder('asc');
     $_GET['sort'] = 'desc';
     $header = array(
-      'id' => array('data' => 'Id', 'specifier' => 'ftid'),
+      'id' => array('data' => 'Id', 'specifier' => 'id'),
       'type' => array('data' => 'Type', 'specifier' => 'fttype'),
     );
-    $this->queryResults = array_values($this->factory->get('test_entity')
+    $this->queryResults = array_values($this->factory->get('entity_test_rev')
       ->tableSort($header)
       ->execute());
     $this->assertBundleOrder('desc');
     // Ordering on ID is definite, however.
     $_GET['order'] = 'Id';
-    $this->queryResults = $this->factory->get('test_entity')
+    $this->queryResults = $this->factory->get('entity_test_rev')
       ->tableSort($header)
       ->execute();
     $this->assertResult(range(15, 1));
@@ -396,7 +410,7 @@ protected function testCount() {
     field_create_instance($instance);
 
     $entity = entity_create('test_entity_bundle', array(
-      'ftid' => 1,
+      'id' => 1,
       'fttype' => $bundle,
     ));
     $entity->enforceIsNew();
@@ -459,7 +473,7 @@ protected function assertBundleOrder($order) {
    * The tags and metadata should propogate to the SQL query object.
    */
   function testMetaData() {
-    $query = entity_query('test_entity');
+    $query = entity_query('entity_test_rev');
     $query
       ->addTag('efq_metadata_test')
       ->addMetaData('foo', 'bar')
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUUIDTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUUIDTest.php
index 5110134..28d0cf7 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUUIDTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUUIDTest.php
@@ -99,6 +99,12 @@ protected function assertCRUD($entity_type) {
           $this->assertNotNull($entity->id());
           $this->assertNotEqual($entity_duplicate->id(), $entity->id());
           break;
+        case 'revision_id':
+          $this->assertNull($entity_duplicate->getRevisionId());
+          $this->assertNotNull($entity->getRevisionId());
+          $this->assertNotEqual($entity_duplicate->getRevisionId(), $entity->getRevisionId());
+          $this->assertNotEqual($entity_duplicate->{$property}->getValue(), $entity->{$property}->getValue());
+          break;
         default:
           $this->assertEqual($entity_duplicate->{$property}->getValue(), $entity->{$property}->getValue());
       }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php b/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php
index c22f222..882ae96 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php
@@ -40,7 +40,7 @@ function testContext() {
     $manager = new MockBlockManager();
     $plugin = $manager->createInstance('user_name');
     // Create a node, add it as context, catch the exception.
-    $node = entity_create('node', array('title' => $name));
+    $node = entity_create('node', array('title' => $name, 'type' => 'page'));
 
     // Try to get a valid context that has not been set.
     try {
diff --git a/core/modules/system/lib/Drupal/system/Tests/Plugin/PluginTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Plugin/PluginTestBase.php
index c927f7e..7b8aa9a 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Plugin/PluginTestBase.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Plugin/PluginTestBase.php
@@ -89,7 +89,7 @@ public function setUp() {
         'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockComplexContextBlock',
         'context' => array(
           'user' => array('class' => 'Drupal\user\Plugin\Core\Entity\User'),
-          'node' => array('class' => 'Drupal\node\Plugin\Core\Entity\Node'),
+          'node' => array('class' => 'Drupal\Core\Entity\EntityBCDecorator'),
         ),
       ),
     );
diff --git a/core/modules/system/lib/Drupal/system/Tests/Theme/EntityFilteringThemeTest.php b/core/modules/system/lib/Drupal/system/Tests/Theme/EntityFilteringThemeTest.php
index 27f3e6a..582c43e 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Theme/EntityFilteringThemeTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Theme/EntityFilteringThemeTest.php
@@ -102,7 +102,7 @@ function setUp() {
       'title' => $this->xss_label,
       'type' => 'article',
       'promote' => NODE_PROMOTED,
-      'field_tags' => array(LANGUAGE_NOT_SPECIFIED => array(array('tid' => $this->term->tid))),
+      'field_tags' => array(array('tid' => $this->term->tid)),
     ));
 
     // Create a test comment on the test node.
@@ -111,7 +111,7 @@ function setUp() {
       'node_type' => $this->node->type,
       'status' => COMMENT_PUBLISHED,
       'subject' => $this->xss_label,
-      'comment_body' => array(LANGUAGE_NOT_SPECIFIED => array($this->randomName())),
+      'comment_body' => array($this->randomName()),
     ));
     comment_save($this->comment);
   }
diff --git a/core/modules/system/tests/modules/entity_test/entity_test.install b/core/modules/system/tests/modules/entity_test/entity_test.install
index dacd1f5..c9c33fc 100644
--- a/core/modules/system/tests/modules/entity_test/entity_test.install
+++ b/core/modules/system/tests/modules/entity_test/entity_test.install
@@ -58,6 +58,13 @@ function entity_test_schema() {
         'length' => 128,
         'not null' => FALSE,
       ),
+      'type' => array(
+        'description' => 'The bundle of the test entity.',
+        'type' => 'varchar',
+        'length' => 32,
+        'not null' => TRUE,
+        'default' => '',
+      ),
       'langcode' => array(
         'description' => 'The {language}.langcode of the original variant of this test entity.',
         'type' => 'varchar',
diff --git a/core/modules/system/tests/modules/entity_test/entity_test.module b/core/modules/system/tests/modules/entity_test/entity_test.module
index e36e47b..faf57b9 100644
--- a/core/modules/system/tests/modules/entity_test/entity_test.module
+++ b/core/modules/system/tests/modules/entity_test/entity_test.module
@@ -64,6 +64,27 @@ function entity_test_entity_info_alter(&$info) {
 }
 
 /**
+ * Implements hook_entity_view_mode_info_alter().
+ */
+function entity_test_entity_view_mode_info_alter(&$view_modes) {
+  $entity_info = entity_get_info();
+  foreach ($entity_info as $entity_type => $info) {
+    if ($entity_info[$entity_type]['module'] == 'entity_test') {
+      $view_modes[$entity_type] = array(
+        'full' => array(
+          'label' => t('Full object'),
+          'custom_settings' => TRUE,
+        ),
+        'teaser' => array(
+          'label' => t('Teaser'),
+          'custom_settings' => TRUE,
+        ),
+      );
+    }
+  }
+}
+
+/**
  * Implements hook_field_extra_fields().
  */
 function entity_test_field_extra_fields() {
@@ -268,3 +289,43 @@ function entity_test_entity_test_insert($entity) {
 function entity_test_label_callback($entity_type, $entity, $langcode = NULL) {
   return 'label callback ' . $entity->name->value;
 }
+
+/**
+ * Creates a new bundle for entity_test entities.
+ *
+ * @param $bundle
+ *   The machine-readable name of the bundle.
+ * @param $text
+ *   The human-readable name of the bundle. If none is provided, the machine
+ *   name will be used.
+ */
+function entity_test_create_bundle($bundle, $text = NULL, $entity_type = 'entity_test') {
+  $bundles = state()->get($entity_type . '.bundles') ?: array('entity_test' => array('label' => 'Entity Test Bundle'));
+  $bundles += array($bundle => array('label' => $text ? $text : $bundle));
+  state()->set($entity_type . '.bundles', $bundles);
+
+  $info = entity_get_info();
+  foreach ($info as $type => $type_info) {
+    if ($type_info['module'] == 'entity_test') {
+      field_attach_create_bundle($type, $bundle);
+    }
+  }
+}
+
+/**
+ * Implements hook_entity_bundle_info_alter().
+ */
+function entity_test_entity_bundle_info_alter(&$bundles) {
+  $entity_info = entity_get_info();
+  foreach ($bundles as $entity_type => $info) {
+    if ($entity_info[$entity_type]['module'] == 'entity_test') {
+      $bundles[$entity_type] = state()->get($entity_type . '.bundles') ?: array($entity_type => array('label' => 'Entity Test Bundle'));
+      /*if ($entity_type == 'test_entity_bundle') {
+        $bundles[$entity_type] += array('test_entity_2' => array('label' => 'Test entity 2'));
+      }
+      if ($entity_type == 'test_entity_bundle_key') {
+        $bundles[$entity_type] += array('bundle1' => array('label' => 'Bundle1'), 'bundle2' => array('label' => 'Bundle2'));
+      }*/
+    }
+  }
+}
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 c08e3b3..f404d13 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
@@ -50,10 +50,35 @@ public function form(array $form, array &$form_state, EntityInterface $entity) {
       '#languages' => LANGUAGE_ALL,
     );
 
+    // @todo: Is there a better way to check if an entity type is revisionable?
+    $entity_info = $entity->entityInfo();
+    if (!empty($entity_info['entity_keys']['revision']) && !$entity->isNew()) {
+      $form['revision'] = array(
+        '#type' => 'checkbox',
+        '#title' => t('Create new revision'),
+        '#default_value' => $entity->isNewRevision(),
+      );
+    }
+
     return $form;
   }
 
   /**
+   * Overrides \Drupal\Core\Entity\EntityFormController::submit().
+   */
+  public function submit(array $form, array &$form_state) {
+    // Build the entity object from the submitted values.
+    $entity = parent::submit($form, $form_state);
+
+    // Save as a new revision if requested to do so.
+    if (!empty($form_state['values']['revision'])) {
+      $entity->setNewRevision();
+    }
+
+    return $entity;
+  }
+
+  /**
    * Overrides Drupal\Core\Entity\EntityFormController::save().
    */
   public function save(array $form, array &$form_state) {
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestStorageController.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestStorageController.php
index 500a41c..ef81ef2 100644
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestStorageController.php
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestStorageController.php
@@ -17,6 +17,13 @@
  */
 class EntityTestStorageController extends DatabaseStorageControllerNG {
 
+  public function create(array $values) {
+    if (empty($values['type'])) {
+      $values['type'] = 'entity_test';
+    }
+    return parent::create($values);
+  }
+
   /**
    * Implements \Drupal\Core\Entity\DataBaseStorageControllerNG::baseFieldDefinitions().
    */
@@ -43,6 +50,11 @@ public function baseFieldDefinitions() {
       'type' => 'string_field',
       'translatable' => TRUE,
     );
+    $fields['type'] = array(
+      'label' => t('Type'),
+      'description' => t('The bundle of the test entity.'),
+      'type' => 'string_field',
+    );
     $fields['user_id'] = array(
       'label' => t('User ID'),
       'description' => t('The ID of the associated user.'),
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTest.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTest.php
index 6396ec3..1db9415 100644
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTest.php
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTest.php
@@ -29,6 +29,7 @@
  *   entity_keys = {
  *     "id" = "id",
  *     "uuid" = "uuid",
+ *     "bundle" = "type",
  *   },
  *   menu_base_path = "entity-test/manage/%entity_test"
  * )
@@ -50,6 +51,15 @@ class EntityTest extends EntityNG {
   public $uuid;
 
   /**
+   * The bundle of the test entity.
+   *
+   * @name: EntityNG already has a bundle property, so we can not use that.
+   *
+   * @var \Drupal\Core\Entity\Field\FieldInterface
+   */
+  public $type;
+
+  /**
    * The name of the test entity.
    *
    * @var \Drupal\Core\Entity\Field\FieldInterface
@@ -73,6 +83,7 @@ protected function init() {
     unset($this->uuid);
     unset($this->name);
     unset($this->user_id);
+    unset($this->type);
   }
 
   /**
diff --git a/core/modules/system/tests/modules/paramconverter_test/lib/Drupal/paramconverter_test/TestControllers.php b/core/modules/system/tests/modules/paramconverter_test/lib/Drupal/paramconverter_test/TestControllers.php
index ddb4833..ca95200 100644
--- a/core/modules/system/tests/modules/paramconverter_test/lib/Drupal/paramconverter_test/TestControllers.php
+++ b/core/modules/system/tests/modules/paramconverter_test/lib/Drupal/paramconverter_test/TestControllers.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\paramconverter_test;
 
-use Drupal\node\Plugin\Core\Entity\Node;
+use Drupal\Core\Entity\EntityInterface;
 
 /**
  * Controller routine for testing the paramconverter.
@@ -21,7 +21,7 @@ public function testUserNodeFoo($user, $node, $foo) {
     return $retval;
   }
 
-  public function testNodeSetParent(Node $node, Node $parent) {
+  public function testNodeSetParent(EntityInterface $node, EntityInterface $parent) {
     return "Setting '{$parent->title}' as parent of '{$node->title}'.";
   }
 }
diff --git a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/MockBlockManager.php b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/MockBlockManager.php
index 7e29259..157e583 100644
--- a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/MockBlockManager.php
+++ b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/MockBlockManager.php
@@ -91,7 +91,7 @@ public function __construct() {
       'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockComplexContextBlock',
       'context' => array(
         'user' => array('class' => 'Drupal\user\Plugin\Core\Entity\User'),
-        'node' => array('class' => 'Drupal\node\Plugin\Core\Entity\Node'),
+        'node' => array('class' => 'Drupal\Core\Entity\EntityBCDecorator'),
       ),
     ));
 
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/field/widget/TaxonomyAutocompleteWidget.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/field/widget/TaxonomyAutocompleteWidget.php
index 0d5dfd4..24e8150 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/field/widget/TaxonomyAutocompleteWidget.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/field/widget/TaxonomyAutocompleteWidget.php
@@ -73,7 +73,7 @@ public function formElement(array $items, $delta, array $element, $langcode, arr
   public function massageFormValues(array $values, array $form, array &$form_state) {
     // Autocomplete widgets do not send their tids in the form, so we must detect
     // them here and process them independently.
-    $terms = array();
+    $items = array();
     $field = $this->field;
 
     // Collect candidate vocabularies.
@@ -89,19 +89,20 @@ public function massageFormValues(array $values, array $form, array &$form_state
       // otherwise, create a new 'autocreate' term for insert/update.
       if ($possibilities = entity_load_multiple_by_properties('taxonomy_term', array('name' => trim($value), 'vid' => array_keys($vocabularies)))) {
         $term = array_pop($possibilities);
+        $item = array('tid' => $term->tid);
       }
       else {
         $vocabulary = reset($vocabularies);
-        $term = array(
-          'tid' => 'autocreate',
+        $term = entity_create('taxonomy_term', array(
           'vid' => $vocabulary->id(),
           'name' => $value,
-        );
+        ));
+        $item = array('tid' => FALSE, 'entity' => $term);
       }
-      $terms[] = (array)$term;
+      $items[] = $item;
     }
 
-    return $terms;
+    return $items;
   }
 
 }
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldMultipleVocabularyTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldMultipleVocabularyTest.php
index 8c5571c..86295f9 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldMultipleVocabularyTest.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldMultipleVocabularyTest.php
@@ -17,7 +17,7 @@ class TermFieldMultipleVocabularyTest extends TaxonomyTestBase {
    *
    * @var array
    */
-  public static $modules = array('field_test');
+  public static $modules = array('entity_test');
 
   protected $instance;
   protected $vocabulary1;
@@ -34,7 +34,7 @@ public static function getInfo() {
   function setUp() {
     parent::setUp();
 
-    $web_user = $this->drupalCreateUser(array('access field_test content', 'administer field_test content', 'administer taxonomy'));
+    $web_user = $this->drupalCreateUser(array('view test entity', 'administer entity_test content', 'administer taxonomy'));
     $this->drupalLogin($web_user);
     $this->vocabulary1 = $this->createVocabulary();
     $this->vocabulary2 = $this->createVocabulary();
@@ -61,14 +61,14 @@ function setUp() {
     field_create_field($this->field);
     $this->instance = array(
       'field_name' => $this->field_name,
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle',
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
       'widget' => array(
         'type' => 'options_select',
       ),
     );
     field_create_instance($this->instance);
-    entity_get_display('test_entity', 'test_bundle', 'full')
+    entity_get_display('entity_test', 'entity_test', 'full')
       ->setComponent($this->field_name, array(
         'type' => 'taxonomy_term_reference_link',
       ))
@@ -85,21 +85,23 @@ function testTaxonomyTermFieldMultipleVocabularies() {
 
     // Submit an entity with both terms.
     $langcode = LANGUAGE_NOT_SPECIFIED;
-    $this->drupalGet('test-entity/add/test_bundle');
+    $this->drupalGet('entity_test/add');
     $this->assertFieldByName("{$this->field_name}[$langcode][]", '', 'Widget is displayed');
     $edit = array(
+      'user_id' => mt_rand(0, 10),
+      'name' => $this->randomName(),
       "{$this->field_name}[$langcode][]" => array($term1->tid, $term2->tid),
     );
     $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
+    preg_match('|entity_test/manage/(\d+)/edit|', $this->url, $match);
     $id = $match[1];
-    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created.');
+    $this->assertText(t('entity_test @id has been created.', array('@id' => $id)), 'Entity was created.');
 
     // Render the entity.
-    $entity = field_test_entity_test_load($id);
-    $entities = array($id => $entity);
+    $entity = entity_load('entity_test', $id);
+    $entities = array($id => $entity->getBCEntity());
     $display = entity_get_display($entity->entityType(), $entity->bundle(), 'full');
-    field_attach_prepare_view('test_entity', $entities, array($entity->bundle() => $display));
+    field_attach_prepare_view('entity_test', $entities, array($entity->bundle() => $display));
     $entity->content = field_attach_view($entity, $display);
     $this->content = drupal_render($entity->content);
     $this->assertText($term1->name, 'Term 1 name is displayed.');
@@ -109,10 +111,10 @@ function testTaxonomyTermFieldMultipleVocabularies() {
     taxonomy_vocabulary_delete($this->vocabulary2->id());
 
     // Re-render the content.
-    $entity = field_test_entity_test_load($id);
-    $entities = array($id => $entity);
+    $entity = entity_load('entity_test', $id);
+    $entities = array($id => $entity->getBCEntity());
     $display = entity_get_display($entity->entityType(), $entity->bundle(), 'full');
-    field_attach_prepare_view('test_entity', $entities, array($entity->bundle() => $display));
+    field_attach_prepare_view('entity_test', $entities, array($entity->bundle() => $display));
     $entity->content = field_attach_view($entity, $display);
     $this->plainTextContent = FALSE;
     $this->content = drupal_render($entity->content);
@@ -126,11 +128,13 @@ function testTaxonomyTermFieldMultipleVocabularies() {
     $this->assertEqual(count($field_info['settings']['allowed_values']), 1, 'Only one vocabulary is allowed for the field.');
 
     // The widget should still be displayed.
-    $this->drupalGet('test-entity/add/test_bundle');
+    $this->drupalGet('entity_test/add');
     $this->assertFieldByName("{$this->field_name}[$langcode][]", '', 'Widget is still displayed');
 
     // Term 1 should still pass validation.
     $edit = array(
+      'user_id' => mt_rand(0, 10),
+      'name' => $this->randomName(),
       "{$this->field_name}[$langcode][]" => array($term1->tid),
     );
     $this->drupalPost(NULL, $edit, t('Save'));
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldTest.php
index d5de5fa..15e6b31 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldTest.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldTest.php
@@ -19,7 +19,7 @@ class TermFieldTest extends TaxonomyTestBase {
    *
    * @var array
    */
-  public static $modules = array('field_test');
+  public static $modules = array('entity_test');
 
   protected $instance;
   protected $vocabulary;
@@ -35,7 +35,11 @@ public static function getInfo() {
   function setUp() {
     parent::setUp();
 
-    $web_user = $this->drupalCreateUser(array('access field_test content', 'administer field_test content', 'administer taxonomy'));
+    $web_user = $this->drupalCreateUser(array(
+      'view test entity',
+      'administer entity_test content',
+      'administer taxonomy',
+    ));
     $this->drupalLogin($web_user);
     $this->vocabulary = $this->createVocabulary();
 
@@ -56,14 +60,14 @@ function setUp() {
     field_create_field($this->field);
     $this->instance = array(
       'field_name' => $this->field_name,
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle',
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
       'widget' => array(
         'type' => 'options_select',
       ),
     );
     field_create_instance($this->instance);
-    entity_get_display('test_entity', 'test_bundle', 'full')
+    entity_get_display('entity_test', 'entity_test', 'full')
       ->setComponent($this->field_name, array(
         'type' => 'taxonomy_term_reference_link',
       ))
@@ -76,22 +80,22 @@ function setUp() {
   function testTaxonomyTermFieldValidation() {
     // Test valid and invalid values with field_attach_validate().
     $langcode = LANGUAGE_NOT_SPECIFIED;
-    $entity = field_test_create_entity();
+    $entity = entity_create('entity_test', array());
     $term = $this->createTerm($this->vocabulary);
-    $entity->{$this->field_name}[$langcode][0]['tid'] = $term->tid;
+    $entity->{$this->field_name}->tid = $term->tid;
     try {
-      field_attach_validate($entity);
+      field_attach_validate($entity->getBCEntity());
       $this->pass('Correct term does not cause validation error.');
     }
     catch (FieldValidationException $e) {
       $this->fail('Correct term does not cause validation error.');
     }
 
-    $entity = field_test_create_entity();
+    $entity = entity_create('entity_test', array());
     $bad_term = $this->createTerm($this->createVocabulary());
-    $entity->{$this->field_name}[$langcode][0]['tid'] = $bad_term->tid;
+    $entity->{$this->field_name}->tid = $bad_term->tid;
     try {
-      field_attach_validate($entity);
+      field_attach_validate($entity->getBCEntity());
       $this->fail('Wrong term causes validation error.');
     }
     catch (FieldValidationException $e) {
@@ -108,30 +112,32 @@ function testTaxonomyTermFieldWidgets() {
 
     // Display creation form.
     $langcode = LANGUAGE_NOT_SPECIFIED;
-    $this->drupalGet('test-entity/add/test_bundle');
+    $this->drupalGet('entity_test/add');
     $this->assertFieldByName("{$this->field_name}[$langcode]", '', 'Widget is displayed.');
 
     // Submit with some value.
     $edit = array(
+      'user_id' => 1,
+      'name' => $this->randomName(),
       "{$this->field_name}[$langcode]" => array($term->tid),
     );
     $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
+    preg_match('|entity_test/manage/(\d+)/edit|', $this->url, $match);
     $id = $match[1];
-    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created.');
+    $this->assertText(t('entity_test @id has been created.', array('@id' => $id)));
 
     // Display the object.
-    $entity = field_test_entity_test_load($id);
-    $entities = array($id => $entity);
+    $entity = entity_load('entity_test', $id);
+    $entities = array($id => $entity->getBCEntity());
     $display = entity_get_display($entity->entityType(), $entity->bundle(), 'full');
-    field_attach_prepare_view('test_entity', $entities, array($entity->bundle() => $display));
+    field_attach_prepare_view('entity_test', $entities, array($entity->bundle() => $display));
     $entity->content = field_attach_view($entity, $display);
     $this->content = drupal_render($entity->content);
     $this->assertText($term->label(), 'Term label is displayed.');
 
     // Delete the vocabulary and verify that the widget is gone.
     taxonomy_vocabulary_delete($this->vocabulary->id());
-    $this->drupalGet('test-entity/add/test_bundle');
+    $this->drupalGet('entity_test/add');
     $this->assertNoFieldByName("{$this->field_name}[$langcode]", '', 'Widget is not displayed');
   }
 
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/Views/TaxonomyTestBase.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/Views/TaxonomyTestBase.php
index ec91070..5f98990 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/Views/TaxonomyTestBase.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/Views/TaxonomyTestBase.php
@@ -54,8 +54,8 @@ function setUp() {
 
     $node = array();
     $node['type'] = 'article';
-    $node['field_views_testing_tags'][LANGUAGE_NOT_SPECIFIED][]['tid'] = $this->term1->tid;
-    $node['field_views_testing_tags'][LANGUAGE_NOT_SPECIFIED][]['tid'] = $this->term2->tid;
+    $node['field_views_testing_tags'][]['tid'] = $this->term1->tid;
+    $node['field_views_testing_tags'][]['tid'] = $this->term2->tid;
     $this->nodes[] = $this->drupalCreateNode($node);
     $this->nodes[] = $this->drupalCreateNode($node);
   }
diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module
index f894d6c..43d2ac8 100644
--- a/core/modules/taxonomy/taxonomy.module
+++ b/core/modules/taxonomy/taxonomy.module
@@ -1067,10 +1067,7 @@ function taxonomy_field_validate(EntityInterface $entity = NULL, $field, $instan
  * Implements hook_field_is_empty().
  */
 function taxonomy_field_is_empty($item, $field) {
-  if (!is_array($item) || (empty($item['tid']) && (string) $item['tid'] !== '0')) {
-    return TRUE;
-  }
-  return FALSE;
+  return !is_array($item) || (empty($item['tid']) && empty($item['entity']));
 }
 
 /**
@@ -1099,9 +1096,8 @@ function taxonomy_field_formatter_info() {
 function taxonomy_field_formatter_view(EntityInterface $entity, $field, $instance, $langcode, $items, $display) {
   $element = array();
 
-  // Terms whose tid is 'autocreate' do not exist
-  // yet and $item['taxonomy_term'] is not set. Theme such terms as
-  // just their name.
+  // Terms whose tid is 'autocreate' do not exist yet and $item['entity'] is not
+  // set. Theme such terms as just their name.
 
   switch ($display['type']) {
     case 'taxonomy_term_reference_link':
@@ -1112,7 +1108,7 @@ function taxonomy_field_formatter_view(EntityInterface $entity, $field, $instanc
           );
         }
         else {
-          $term = $item['taxonomy_term'];
+          $term = $item['entity'];
           $uri = $term->uri();
           $element[$delta] = array(
             '#type' => 'link',
@@ -1126,7 +1122,7 @@ function taxonomy_field_formatter_view(EntityInterface $entity, $field, $instanc
 
     case 'taxonomy_term_reference_plain':
       foreach ($items as $delta => $item) {
-        $name = ($item['tid'] != 'autocreate' ? $item['taxonomy_term']->label() : $item['name']);
+        $name = ($item['tid'] != 'autocreate' ? $item['entity']->label() : $item['name']);
         $element[$delta] = array(
           '#markup' => check_plain($name),
         );
@@ -1137,7 +1133,7 @@ function taxonomy_field_formatter_view(EntityInterface $entity, $field, $instanc
       foreach ($items as $delta => $item) {
         $entity->rss_elements[] = array(
           'key' => 'category',
-          'value' => $item['tid'] != 'autocreate' ? $item['taxonomy_term']->label() : $item['name'],
+          'value' => $item['tid'] != 'autocreate' ? $item['entity']->label() : $item['name'],
           'attributes' => array(
             'domain' => $item['tid'] != 'autocreate' ? url('taxonomy/term/' . $item['tid'], array('absolute' => TRUE)) : '',
           ),
@@ -1192,7 +1188,7 @@ function taxonomy_field_formatter_prepare_view($entity_type, $entities, $field,
   foreach ($entities as $id => $entity) {
     foreach ($items[$id] as $delta => $item) {
       // Force the array key to prevent duplicates.
-      if ($item['tid'] != 'autocreate') {
+      if ($item['tid'] != 'autocreate' && $item['tid'] !== FALSE) {
         $tids[$item['tid']] = $item['tid'];
       }
     }
@@ -1208,7 +1204,7 @@ function taxonomy_field_formatter_prepare_view($entity_type, $entities, $field,
         // Check whether the taxonomy term field instance value could be loaded.
         if (isset($terms[$item['tid']])) {
           // Replace the instance value with the term data.
-          $items[$id][$delta]['taxonomy_term'] = $terms[$item['tid']];
+          $items[$id][$delta]['entity'] = $terms[$item['tid']];
         }
         // Terms to be created are not in $terms, but are still legitimate.
         elseif ($item['tid'] == 'autocreate') {
@@ -1358,12 +1354,10 @@ function taxonomy_rdf_mapping() {
  */
 function taxonomy_field_presave(EntityInterface $entity, $field, $instance, $langcode, &$items) {
   foreach ($items as $delta => $item) {
-    if ($item['tid'] == 'autocreate') {
+    if (!$item['tid'] && isset($item['entity'])) {
       unset($item['tid']);
-      $term = entity_create('taxonomy_term', $item);
-      $term->langcode = $langcode;
-      taxonomy_term_save($term);
-      $items[$delta]['tid'] = $term->tid;
+      taxonomy_term_save($item['entity']);
+      $items[$delta]['tid'] = $item['entity']->tid;
     }
   }
 }
@@ -1371,7 +1365,7 @@ function taxonomy_field_presave(EntityInterface $entity, $field, $instance, $lan
 /**
  * Implements hook_node_insert().
  */
-function taxonomy_node_insert(Node $node) {
+function taxonomy_node_insert(EntityInterface $node) {
   // Add taxonomy index entries for the node.
   taxonomy_build_node_index($node);
 }
@@ -1448,7 +1442,7 @@ function taxonomy_build_node_index($node) {
 /**
  * Implements hook_node_update().
  */
-function taxonomy_node_update(Node $node) {
+function taxonomy_node_update(EntityInterface $node) {
   // Always rebuild the node's taxonomy index entries on node save.
   taxonomy_delete_node_index($node);
   taxonomy_build_node_index($node);
@@ -1457,7 +1451,7 @@ function taxonomy_node_update(Node $node) {
 /**
  * Implements hook_node_predelete().
  */
-function taxonomy_node_predelete(Node $node) {
+function taxonomy_node_predelete(EntityInterface $node) {
   // Clean up the {taxonomy_index} table when nodes are deleted.
   taxonomy_delete_node_index($node);
 }
@@ -1465,10 +1459,10 @@ function taxonomy_node_predelete(Node $node) {
 /**
  * Deletes taxonomy index entries for a given node.
  *
- * @param Drupal\node\Plugin\Core\Entity\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node entity.
  */
-function taxonomy_delete_node_index(Node $node) {
+function taxonomy_delete_node_index(EntityInterface $node) {
   if (config('taxonomy.settings')->get('maintain_index_table')) {
     db_delete('taxonomy_index')->condition('nid', $node->nid)->execute();
   }
diff --git a/core/modules/text/lib/Drupal/text/Tests/TextFieldTest.php b/core/modules/text/lib/Drupal/text/Tests/TextFieldTest.php
index f8c585b..00430ec 100644
--- a/core/modules/text/lib/Drupal/text/Tests/TextFieldTest.php
+++ b/core/modules/text/lib/Drupal/text/Tests/TextFieldTest.php
@@ -20,7 +20,7 @@ class TextFieldTest extends WebTestBase {
    *
    * @var array
    */
-  public static $modules = array('field_test');
+  public static $modules = array('entity_test');
 
   protected $instance;
   protected $admin_user;
@@ -38,7 +38,7 @@ function setUp() {
     parent::setUp();
 
     $this->admin_user = $this->drupalCreateUser(array('administer filters'));
-    $this->web_user = $this->drupalCreateUser(array('access field_test content', 'administer field_test content'));
+    $this->web_user = $this->drupalCreateUser(array('view test entity', 'administer entity_test content'));
     $this->drupalLogin($this->web_user);
   }
 
@@ -60,24 +60,24 @@ function testTextFieldValidation() {
     field_create_field($this->field);
     $this->instance = array(
       'field_name' => $this->field['field_name'],
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle',
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
       'widget' => array(
         'type' => 'text_textfield',
       ),
     );
     field_create_instance($this->instance);
-    entity_get_display('test_entity', 'test_bundle', 'default')
+    entity_get_display('entity_test', 'entity_test', 'default')
       ->setComponent($this->field['field_name'])
       ->save();
 
     // Test valid and invalid values with field_attach_validate().
-    $entity = field_test_create_entity();
+    $entity = entity_create('entity_test', array());
     $langcode = LANGUAGE_NOT_SPECIFIED;
     for ($i = 0; $i <= $max_length + 2; $i++) {
-      $entity->{$this->field['field_name']}[$langcode][0]['value'] = str_repeat('x', $i);
+      $entity->{$this->field['field_name']}->value = str_repeat('x', $i);
       try {
-        field_attach_validate($entity);
+        field_attach_validate($entity->getBCEntity());
         $this->assertTrue($i <= $max_length, "Length $i does not cause validation error when max_length is $max_length");
       }
       catch (FieldValidationException $e) {
@@ -99,14 +99,14 @@ function testTextfieldWidgets() {
    */
   function _testTextfieldWidgets($field_type, $widget_type) {
     // Setup a field and instance
-    $entity_type = 'test_entity';
+    $entity_type = 'entity_test';
     $this->field_name = drupal_strtolower($this->randomName());
     $this->field = array('field_name' => $this->field_name, 'type' => $field_type);
     field_create_field($this->field);
     $this->instance = array(
       'field_name' => $this->field_name,
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle',
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
       'label' => $this->randomName() . '_label',
       'settings' => array(
         'text_processing' => TRUE,
@@ -119,14 +119,14 @@ function _testTextfieldWidgets($field_type, $widget_type) {
       ),
     );
     field_create_instance($this->instance);
-    entity_get_display('test_entity', 'test_bundle', 'full')
+    entity_get_display('entity_test', 'entity_test', 'full')
       ->setComponent($this->field_name)
       ->save();
 
     $langcode = LANGUAGE_NOT_SPECIFIED;
 
     // Display creation form.
-    $this->drupalGet('test-entity/add/test_bundle');
+    $this->drupalGet('entity_test/add');
     $this->assertFieldByName("{$this->field_name}[$langcode][0][value]", '', 'Widget is displayed');
     $this->assertNoFieldByName("{$this->field_name}[$langcode][0][format]", '1', 'Format selector is not displayed');
     $this->assertRaw(format_string('placeholder="A placeholder on !widget_type"', array('!widget_type' => $widget_type)));
@@ -134,18 +134,20 @@ function _testTextfieldWidgets($field_type, $widget_type) {
     // Submit with some value.
     $value = $this->randomName();
     $edit = array(
+      'user_id' => 1,
+      'name' => $this->randomName(),
       "{$this->field_name}[$langcode][0][value]" => $value,
     );
     $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
+    preg_match('|entity_test/manage/(\d+)/edit|', $this->url, $match);
     $id = $match[1];
-    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created');
+    $this->assertText(t('entity_test @id has been created.', array('@id' => $id)), 'Entity was created');
 
     // Display the entity.
-    $entity = field_test_entity_test_load($id);
+    $entity = entity_load('entity_test', $id);
     $display = entity_get_display($entity->entityType(), $entity->bundle(), 'full');
-    $entity->content = field_attach_view($entity, $display);
-    $this->content = drupal_render($entity->content);
+    $entity->content = field_attach_view($entity->getBCEntity(), $display);
+    $this->drupalSetContent(drupal_render($entity->content));
     $this->assertText($value, 'Filtered tags are not displayed');
   }
 
@@ -162,14 +164,13 @@ function testTextfieldWidgetsFormatted() {
    */
   function _testTextfieldWidgetsFormatted($field_type, $widget_type) {
     // Setup a field and instance
-    $entity_type = 'test_entity';
     $this->field_name = drupal_strtolower($this->randomName());
     $this->field = array('field_name' => $this->field_name, 'type' => $field_type);
     field_create_field($this->field);
     $this->instance = array(
       'field_name' => $this->field_name,
-      'entity_type' => 'test_entity',
-      'bundle' => 'test_bundle',
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
       'label' => $this->randomName() . '_label',
       'settings' => array(
         'text_processing' => TRUE,
@@ -179,7 +180,7 @@ function _testTextfieldWidgetsFormatted($field_type, $widget_type) {
       ),
     );
     field_create_instance($this->instance);
-    entity_get_display('test_entity', 'test_bundle', 'full')
+    entity_get_display('entity_test', 'entity_test', 'full')
       ->setComponent($this->field_name)
       ->save();
 
@@ -196,24 +197,26 @@ function _testTextfieldWidgetsFormatted($field_type, $widget_type) {
 
     // Display the creation form. Since the user only has access to one format,
     // no format selector will be displayed.
-    $this->drupalGet('test-entity/add/test_bundle');
+    $this->drupalGet('entity_test/add');
     $this->assertFieldByName("{$this->field_name}[$langcode][0][value]", '', 'Widget is displayed');
     $this->assertNoFieldByName("{$this->field_name}[$langcode][0][format]", '', 'Format selector is not displayed');
 
     // Submit with data that should be filtered.
     $value = '<em>' . $this->randomName() . '</em>';
     $edit = array(
+      'user_id' => 1,
+      'name' => $this->randomName(),
       "{$this->field_name}[$langcode][0][value]" => $value,
     );
     $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
+    preg_match('|entity_test/manage/(\d+)/edit|', $this->url, $match);
     $id = $match[1];
-    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created');
+    $this->assertText(t('entity_test @id has been created.', array('@id' => $id)), 'Entity was created');
 
     // Display the entity.
-    $entity = field_test_entity_test_load($id);
+    $entity = entity_load('entity_test', $id);
     $display = entity_get_display($entity->entityType(), $entity->bundle(), 'full');
-    $entity->content = field_attach_view($entity, $display);
+    $entity->content = field_attach_view($entity->getBCEntity(), $display);
     $this->content = drupal_render($entity->content);
     $this->assertNoRaw($value, 'HTML tags are not displayed.');
     $this->assertRaw(check_plain($value), 'Escaped HTML is displayed correctly.');
@@ -239,22 +242,24 @@ function _testTextfieldWidgetsFormatted($field_type, $widget_type) {
 
     // Display edition form.
     // We should now have a 'text format' selector.
-    $this->drupalGet('test-entity/manage/' . $id . '/edit');
+    $this->drupalGet('entity_test/manage/' . $id . '/edit');
     $this->assertFieldByName("{$this->field_name}[$langcode][0][value]", NULL, 'Widget is displayed');
     $this->assertFieldByName("{$this->field_name}[$langcode][0][format]", NULL, 'Format selector is displayed');
 
     // Edit and change the text format to the new one that was created.
     $edit = array(
+      'user_id' => 1,
+      'name' => $this->randomName(),
       "{$this->field_name}[$langcode][0][format]" => $format_id,
     );
     $this->drupalPost(NULL, $edit, t('Save'));
-    $this->assertRaw(t('test_entity @id has been updated.', array('@id' => $id)), 'Entity was updated');
+    $this->assertText(t('entity_test @id has been updated.', array('@id' => $id)), 'Entity was updated');
 
     // Display the entity.
-    $this->container->get('plugin.manager.entity')->getStorageController('test_entity')->resetCache(array($id));
-    $entity = field_test_entity_test_load($id);
+    $this->container->get('plugin.manager.entity')->getStorageController('entity_test')->resetCache(array($id));
+    $entity = entity_load('entity_test', $id);
     $display = entity_get_display($entity->entityType(), $entity->bundle(), 'full');
-    $entity->content = field_attach_view($entity, $display);
+    $entity->content = field_attach_view($entity->getBCEntity(), $display);
     $this->content = drupal_render($entity->content);
     $this->assertRaw($value, 'Value is displayed unfiltered');
   }
diff --git a/core/modules/tracker/tracker.module b/core/modules/tracker/tracker.module
index 30a0dbb..125b5da 100644
--- a/core/modules/tracker/tracker.module
+++ b/core/modules/tracker/tracker.module
@@ -5,7 +5,7 @@
  * Tracks recent content posted by a user or users.
  */
 
-use Drupal\node\Plugin\Core\Entity\Node;
+use Drupal\Core\Entity\EntityInterface;
 
 /**
  * Implements hook_help().
@@ -193,7 +193,7 @@ function _tracker_user_access($account) {
  *
  * Adds new tracking information for this node since it's new.
  */
-function tracker_node_insert(Node $node, $arg = 0) {
+function tracker_node_insert(EntityInterface $node, $arg = 0) {
   _tracker_add($node->nid, $node->uid, $node->changed);
 }
 
@@ -202,7 +202,7 @@ function tracker_node_insert(Node $node, $arg = 0) {
  *
  * Adds tracking information for this node since it's been updated.
  */
-function tracker_node_update(Node $node, $arg = 0) {
+function tracker_node_update(EntityInterface $node, $arg = 0) {
   _tracker_add($node->nid, $node->uid, $node->changed);
 }
 
@@ -211,7 +211,7 @@ function tracker_node_update(Node $node, $arg = 0) {
  *
  * Deletes tracking information for a node.
  */
-function tracker_node_predelete(Node $node, $arg = 0) {
+function tracker_node_predelete(EntityInterface $node, $arg = 0) {
   db_delete('tracker_node')
     ->condition('nid', $node->nid)
     ->execute();
diff --git a/core/modules/tracker/tracker.pages.inc b/core/modules/tracker/tracker.pages.inc
index 853f50d..a801ad7 100644
--- a/core/modules/tracker/tracker.pages.inc
+++ b/core/modules/tracker/tracker.pages.inc
@@ -37,7 +37,7 @@ function tracker_page($account = NULL, $set_title = FALSE) {
 
   // This array acts as a placeholder for the data selected later
   // while keeping the correct order.
-  $nodes = $query
+  $tracker_data = $query
     ->addTag('node_access')
     ->addMetaData('base_table', 'tracker_node')
     ->fields('t', array('nid', 'changed'))
@@ -48,12 +48,14 @@ function tracker_page($account = NULL, $set_title = FALSE) {
     ->fetchAllAssoc('nid');
 
   $rows = array();
-  if (!empty($nodes)) {
+  if (!empty($tracker_data)) {
+    $nids = array_keys($tracker_data);
+    $nodes = entity_load_multiple('node', $nids);
     // Now, get the data and put into the placeholder array.
-    $result = db_query('SELECT n.nid, n.title, n.type, n.changed, n.uid, u.name, l.comment_count FROM {node} n INNER JOIN {node_comment_statistics} l ON n.nid = l.nid INNER JOIN {users} u ON n.uid = u.uid WHERE n.nid IN (:nids)', array(':nids' => array_keys($nodes)), array('target' => 'slave'));
-    foreach ($result as $node) {
-      $node->last_activity = $nodes[$node->nid]->changed;
-      $nodes[$node->nid] = $node;
+    $result = db_query('SELECT n.nid, l.comment_count FROM {node} n INNER JOIN {node_comment_statistics} l ON n.nid = l.nid INNER JOIN {users} u ON n.uid = u.uid WHERE n.nid IN (:nids)', array(':nids' => $nids), array('target' => 'slave'))->fetchAllKeyed();
+    foreach ($result as $nid => $comment_count) {
+      $nodes[$nid]->last_activity = $tracker_data[$nid]->changed;
+      $nodes[$nid]->comment_count = $comment_count;
     }
 
     // Display the data.
diff --git a/core/modules/translation/lib/Drupal/translation/Tests/TranslationTest.php b/core/modules/translation/lib/Drupal/translation/Tests/TranslationTest.php
index 6e3dccf..df2c386 100644
--- a/core/modules/translation/lib/Drupal/translation/Tests/TranslationTest.php
+++ b/core/modules/translation/lib/Drupal/translation/Tests/TranslationTest.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\translation\Tests;
 
-use Drupal\node\Plugin\Core\Entity\Node;
+use Drupal\Core\Entity\EntityInterface;
 use Drupal\simpletest\WebTestBase;
 
 /**
@@ -362,7 +362,7 @@ function createPage($title, $body, $langcode = NULL) {
   /**
    * Creates a translation for a basic page in the specified language.
    *
-   * @param Drupal\node\Node $node
+   * @param \Drupal\Core\Entity\EntityInterface $node
    *   The basic page to create the translation for.
    * @param $title
    *   The title of a basic page in the specified language.
@@ -374,7 +374,7 @@ function createPage($title, $body, $langcode = NULL) {
    * @return
    *   Translation object.
    */
-  function createTranslation(Node $node, $title, $body, $langcode) {
+  function createTranslation(EntityInterface $node, $title, $body, $langcode) {
     $this->drupalGet('node/add/page', array('query' => array('translation' => $node->nid, 'target' => $langcode)));
 
     $field_langcode = LANGUAGE_NOT_SPECIFIED;
diff --git a/core/modules/translation/tests/translation_test.module b/core/modules/translation/tests/translation_test.module
index d5db14d..3b7fe76 100644
--- a/core/modules/translation/tests/translation_test.module
+++ b/core/modules/translation/tests/translation_test.module
@@ -5,11 +5,11 @@
  * Mock module for content translation tests.
  */
 
-use Drupal\node\Plugin\Core\Entity\Node;
+use Drupal\Core\Entity\EntityInterface;
 
 /**
  * Implements hook_node_insert().
  */
-function translation_test_node_insert(Node $node) {
-  drupal_write_record('node', $node, 'nid');
+function translation_test_node_insert(EntityInterface $node) {
+  $node->save();
 }
diff --git a/core/modules/translation/translation.module b/core/modules/translation/translation.module
index a864120..41d8e83 100644
--- a/core/modules/translation/translation.module
+++ b/core/modules/translation/translation.module
@@ -19,7 +19,7 @@
  *   date (0) or needs to be updated (1).
  */
 
-use Drupal\node\Plugin\Core\Entity\Node;
+use Drupal\Core\Entity\EntityInterface;
 use Drupal\entity\Plugin\Core\Entity\EntityDisplay;
 
 /**
@@ -248,7 +248,7 @@ function translation_form_node_form_alter(&$form, &$form_state) {
  * translation set. If no language provider is enabled, "fall back" to simple
  * links built through the result of translation_node_get_translations().
  */
-function translation_node_view(Node $node, EntityDisplay $display, $view_mode) {
+function translation_node_view(EntityInterface $node, EntityDisplay $display, $view_mode) {
   // If the site has no translations or is not multilingual we have no content
   // translation links to display.
   if (isset($node->tnid) && language_multilingual() && $translations = translation_node_get_translations($node->tnid)) {
@@ -302,7 +302,7 @@ function translation_node_view(Node $node, EntityDisplay $display, $view_mode) {
 /**
  * Implements hook_node_prepare().
  */
-function translation_node_prepare(Node $node) {
+function translation_node_prepare(EntityInterface $node) {
   // Only act if we are dealing with a content type supporting translations.
   if (translation_supported_type($node->type) &&
     // And it's a new node.
@@ -344,7 +344,7 @@ function translation_node_prepare(Node $node) {
 /**
  * Implements hook_node_insert().
  */
-function translation_node_insert(Node $node) {
+function translation_node_insert(EntityInterface $node) {
   // Only act if we are dealing with a content type supporting translations.
   if (translation_supported_type($node->type)) {
     if (!empty($node->translation_source)) {
@@ -379,7 +379,7 @@ function translation_node_insert(Node $node) {
 /**
  * Implements hook_node_update().
  */
-function translation_node_update(Node $node) {
+function translation_node_update(EntityInterface $node) {
   // Only act if we are dealing with a content type supporting translations.
   if (translation_supported_type($node->type)) {
     if (isset($node->translation) && $node->translation && !empty($node->langcode) && $node->tnid) {
@@ -408,7 +408,7 @@ function translation_node_update(Node $node) {
  *
  * Ensures that duplicate translations can't be created for the same source.
  */
-function translation_node_validate(Node $node, $form, &$form_state) {
+function translation_node_validate(EntityInterface $node, $form, &$form_state) {
   // Only act on translatable nodes with a tnid or translation_source.
   $form_node = $form_state['controller']->getEntity($form_state);
   if (translation_supported_type($node->type) && (!empty($node->tnid) || !empty($form_node->translation_source->nid))) {
@@ -423,7 +423,7 @@ function translation_node_validate(Node $node, $form, &$form_state) {
 /**
  * Implements hook_node_predelete().
  */
-function translation_node_predelete(Node $node) {
+function translation_node_predelete(EntityInterface $node) {
   // Only act if we are dealing with a content type supporting translations.
   if (translation_supported_type($node->type)) {
     translation_remove_from_set($node);
diff --git a/core/modules/translation/translation.pages.inc b/core/modules/translation/translation.pages.inc
index 181b6c8..5412d2f 100644
--- a/core/modules/translation/translation.pages.inc
+++ b/core/modules/translation/translation.pages.inc
@@ -6,12 +6,12 @@
  */
 
 use Drupal\Component\Utility\NestedArray;
-use Drupal\node\Plugin\Core\Entity\Node;
+use Drupal\Core\Entity\EntityInterface;
 
 /**
  * Page callback: Displays a list of a node's translations.
  *
- * @param Drupal\node\Node $node
+ * @param \Drupal\Core\Entity\EntityInterface $node
  *   A node entity.
  *
  * @return
@@ -19,7 +19,7 @@
  *
  * @see translation_menu()
  */
-function translation_node_overview(Node $node) {
+function translation_node_overview(EntityInterface $node) {
   include_once DRUPAL_ROOT . '/core/includes/language.inc';
 
   if ($node->tnid) {
diff --git a/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationUITest.php b/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationUITest.php
index 3a9e15b..16eb88b 100644
--- a/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationUITest.php
+++ b/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationUITest.php
@@ -66,7 +66,7 @@ protected function assertBasicTranslation() {
 
     $base_path = $this->controller->getBasePath($entity);
     $path = $langcode . '/' . $base_path . '/translations/add/' . $default_langcode . '/' . $langcode;
-    $this->drupalPost($path, $this->getEditValues($values, $langcode), $this->getFormSubmitAction());
+    $this->drupalPost($path, $this->getEditValues($values, $langcode), $this->getFormSubmitAction($entity));
     if ($this->testLanguageSelector) {
       $this->assertNoFieldByXPath('//select[@id="edit-langcode"]', NULL, 'Language selector correclty disabled on translations.');
     }
@@ -83,7 +83,7 @@ protected function assertBasicTranslation() {
     // Add another translation and mark the other ones as outdated.
     $values[$langcode] = $this->getNewEntityValues($langcode);
     $edit = $this->getEditValues($values, $langcode) + array('translation_entity[retranslate]' => TRUE);
-    $this->drupalPost($path, $edit, $this->getFormSubmitAction());
+    $this->drupalPost($path, $edit, $this->getFormSubmitAction($entity));
     $entity = entity_load($this->entityType, $this->entityId, TRUE);
 
     // Check that the entered values have been correctly stored.
@@ -108,7 +108,7 @@ protected function assertOutdatedStatus() {
 
     // Mark translations as outdated.
     $edit = array('translation_entity[retranslate]' => TRUE);
-    $this->drupalPost($langcode . '/' . $this->controller->getEditPath($entity), $edit, $this->getFormSubmitAction());
+    $this->drupalPost($langcode . '/' . $this->controller->getEditPath($entity), $edit, $this->getFormSubmitAction($entity));
     $entity = entity_load($this->entityType, $this->entityId, TRUE);
 
     // Check that every translation has the correct "outdated" status.
@@ -122,7 +122,7 @@ protected function assertOutdatedStatus() {
       else {
         $this->assertFieldByXPath('//input[@name="translation_entity[outdated]"]', TRUE, 'The translate flag is checked by default.');
         $edit = array('translation_entity[outdated]' => FALSE);
-        $this->drupalPost($path, $edit, $this->getFormSubmitAction());
+        $this->drupalPost($path, $edit, $this->getFormSubmitAction($entity));
         $this->drupalGet($path);
         $this->assertFieldByXPath('//input[@name="translation_entity[retranslate]"]', FALSE, 'The retranslate flag is now shown.');
         $entity = entity_load($this->entityType, $this->entityId, TRUE);
@@ -142,7 +142,7 @@ protected function assertPublishedStatus() {
     foreach ($this->langcodes as $index => $langcode) {
       if ($index > 0) {
         $edit = array('translation_entity[status]' => FALSE);
-        $this->drupalPost($langcode . '/' . $path, $edit, $this->getFormSubmitAction());
+        $this->drupalPost($langcode . '/' . $path, $edit, $this->getFormSubmitAction($entity));
         $entity = entity_load($this->entityType, $this->entityId, TRUE);
         $this->assertFalse($entity->translation[$langcode]['status'], 'The translation has been correctly unpublished.');
       }
@@ -173,7 +173,7 @@ protected function assertAuthoringInfo() {
         'translation_entity[created]' => format_date($values[$langcode]['created'], 'custom', 'Y-m-d H:i:s O'),
       );
       $prefix = $index > 0 ? $langcode . '/' : '';
-      $this->drupalPost($prefix . $path, $edit, $this->getFormSubmitAction());
+      $this->drupalPost($prefix . $path, $edit, $this->getFormSubmitAction($entity));
     }
 
     $entity = entity_load($this->entityType, $this->entityId, TRUE);
@@ -189,7 +189,7 @@ protected function assertAuthoringInfo() {
       'translation_entity[name]' => $this->randomName(12),
       'translation_entity[created]' => $this->randomName(),
     );
-    $this->drupalPost($path, $edit, $this->getFormSubmitAction());
+    $this->drupalPost($path, $edit, $this->getFormSubmitAction($entity));
     $this->assertTrue($this->xpath('//div[@id="messages"]//div[contains(@class, "error")]//ul'), 'Invalid values generate a list of form errors.');
     $this->assertEqual($entity->translation[$langcode]['uid'] == $values[$langcode]['uid'], 'Translation author correctly kept.');
     $this->assertEqual($entity->translation[$langcode]['created'] == $values[$langcode]['created'], 'Translation date correctly kept.');
@@ -235,8 +235,14 @@ protected function getEditValues($values, $langcode, $new = FALSE) {
 
   /**
    * Returns the form action value to be used to submit the entity form.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity being tested.
+   *
+   * @return string
+   *   Name of the button to hit.
    */
-  protected function getFormSubmitAction() {
+  protected function getFormSubmitAction(EntityInterface $entity) {
     return t('Save');
   }
 
@@ -252,6 +258,8 @@ protected function getFormSubmitAction() {
    *   The translation object to act on.
    */
   protected function getTranslation(EntityInterface $entity, $langcode) {
+    // @todo remove once EntityBCDecorator is gone.
+    $entity = $entity->getOriginalEntity();
     return $entity instanceof EntityNG ? $entity->getTranslation($langcode, FALSE) : $entity;
   }
 
@@ -270,7 +278,8 @@ protected function getTranslation(EntityInterface $entity, $langcode) {
    */
   protected function getValue(ComplexDataInterface $translation, $property, $langcode) {
     $key = $property == 'user_id' ? 'target_id' : 'value';
-    if (($translation instanceof EntityInterface) && !($translation instanceof EntityNG)) {
+    // @todo remove EntityBCDecorator condition once EntityBCDecorator is gone.
+    if (($translation instanceof EntityInterface) && !($translation instanceof EntityNG) && !($translation instanceof EntityBCDecorator)) {
       return is_array($translation->$property) ? $translation->{$property}[$langcode][0][$key] : $translation->$property;
     }
     else {
diff --git a/core/modules/translation_entity/translation_entity.module b/core/modules/translation_entity/translation_entity.module
index ac00322..1e4a072 100644
--- a/core/modules/translation_entity/translation_entity.module
+++ b/core/modules/translation_entity/translation_entity.module
@@ -614,6 +614,8 @@ function translation_entity_form_alter(array &$form, array &$form_state) {
     // Handle fields shared between translations when there is at least one
     // translation available or a new one is being created.
     if (!$entity->isNew() && (!isset($translations[$form_langcode]) || count($translations) > 1)) {
+      // @todo remove once EntityBCDecorator is gone.
+      $entity = $entity->getOriginalEntity();
       if ($entity instanceof EntityNG) {
         foreach ($entity->getPropertyDefinitions() as $property_name => $definition) {
           if (isset($form[$property_name])) {
diff --git a/core/modules/translation_entity/translation_entity.pages.inc b/core/modules/translation_entity/translation_entity.pages.inc
index f0c3027..9c740f7 100644
--- a/core/modules/translation_entity/translation_entity.pages.inc
+++ b/core/modules/translation_entity/translation_entity.pages.inc
@@ -238,6 +238,8 @@ function translation_entity_edit_page(EntityInterface $entity, Language $languag
 function translation_entity_prepare_translation(EntityInterface $entity, Language $source, Language $target) {
   // @todo Unify field and property handling.
   $instances = field_info_instances($entity->entityType(), $entity->bundle());
+  // @todo remove once EntityBCDecorator is gone.
+  $entity = $entity->getOriginalEntity();
   if ($entity instanceof EntityNG) {
     $source_translation = $entity->getTranslation($source->langcode);
     $target_translation = $entity->getTranslation($target->langcode);
diff --git a/core/modules/views/lib/Drupal/views/Tests/DefaultViewsTest.php b/core/modules/views/lib/Drupal/views/Tests/DefaultViewsTest.php
index 7e8fc93..c4f90b8 100644
--- a/core/modules/views/lib/Drupal/views/Tests/DefaultViewsTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/DefaultViewsTest.php
@@ -44,6 +44,9 @@ public static function getInfo() {
   protected function setUp() {
     parent::setUp();
 
+    // Create Basic page node type.
+    $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
+
     $this->vocabulary = entity_create('taxonomy_vocabulary', array(
       'name' => $this->randomName(),
       'description' => $this->randomName(),
@@ -93,13 +96,13 @@ protected function setUp() {
       $term = $this->createTerm($this->vocabulary);
 
       $values = array('created' => $time, 'type' => 'page');
-      $values[$this->field_name][LANGUAGE_NOT_SPECIFIED][]['tid'] = $term->tid;
+      $values[$this->field_name][]['tid'] = $term->tid;
 
       // Make every other node promoted.
       if ($i % 2) {
         $values['promote'] = TRUE;
       }
-      $values['body'][LANGUAGE_NOT_SPECIFIED][]['value'] = l('Node ' . 1, 'node/' . 1);
+      $values['body'][]['value'] = l('Node ' . 1, 'node/' . 1);
 
       $node = $this->drupalCreateNode($values);
 
