diff --git a/core/lib/Drupal/Core/Entity/ContentEntityBase.php b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
index aac1cbb..16fd237 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityBase.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
@@ -9,7 +9,6 @@
 
 use Drupal\Component\Utility\String;
 use Drupal\Core\Entity\Plugin\DataType\EntityReference;
-use Drupal\Core\Entity\TypedData\EntityDataDefinition;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\TypedData\TypedDataInterface;
@@ -131,13 +130,6 @@
   protected $entityKeys = array();
 
   /**
-   * The instantiated entity data definition.
-   *
-   * @var \Drupal\Core\Entity\TypedData\EntityDataDefinition
-   */
-  protected $dataDefinition;
-
-  /**
    * Overrides Entity::__construct().
    */
   public function __construct(array $values, $entity_type, $bundle = FALSE, $translations = array()) {
@@ -259,98 +251,8 @@ public function preSaveRevision(EntityStorageInterface $storage, \stdClass $reco
   /**
    * {@inheritdoc}
    */
-  public function getDataDefinition() {
-    if (!$this->dataDefinition) {
-      $this->dataDefinition = EntityDataDefinition::create($this->getEntityTypeId());
-      $this->dataDefinition->setBundles(array($this->bundle()));
-    }
-    return $this->dataDefinition;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getValue() {
-    // @todo: This does not make much sense, so remove once TypedDataInterface
-    // is removed. See https://drupal.org/node/2002138.
-    return $this->toArray();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setValue($value, $notify = TRUE) {
-    // @todo: This does not make much sense, so remove once TypedDataInterface
-    // is removed. See https://drupal.org/node/2002138.
-    foreach ($value as $field_name => $field_value) {
-      $this->set($field_name, $field_value, $notify);
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getString() {
-    return (string) $this->label();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function validate() {
-    return $this->typedDataManager()->getValidator()->validate($this);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function applyDefaultValue($notify = TRUE) {
-    foreach ($this->getProperties() as $property) {
-      $property->applyDefaultValue(FALSE);
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getConstraints() {
-    return array();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getName() {
-    return NULL;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getRoot() {
-    return $this;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getPropertyPath() {
-    return '';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getParent() {
-    return NULL;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setContext($name = NULL, TypedDataInterface $parent = NULL) {
-    // As entities are always the root of the tree of typed data, we do not need
-    // to set any parent or name.
+    return $this->getTypedData()->validate();
   }
 
   /**
@@ -374,7 +276,6 @@ public function __sleep() {
     }
     $this->fields = array();
     $this->fieldDefinitions = NULL;
-    $this->dataDefinition = NULL;
     $this->clearTranslationCache();
 
     return parent::__sleep();
@@ -411,11 +312,11 @@ public function hasField($field_name) {
   /**
    * {@inheritdoc}
    */
-  public function get($property_name) {
-    if (!isset($this->fields[$property_name][$this->activeLangcode])) {
-      return $this->getTranslatedField($property_name, $this->activeLangcode);
+  public function get($field_name) {
+    if (!isset($this->fields[$field_name][$this->activeLangcode])) {
+      return $this->getTranslatedField($field_name, $this->activeLangcode);
     }
-    return $this->fields[$property_name][$this->activeLangcode];
+    return $this->fields[$field_name][$this->activeLangcode];
   }
 
   /**
@@ -450,7 +351,8 @@ protected function getTranslatedField($name, $langcode) {
         if (isset($this->values[$name][$langcode])) {
           $value = $this->values[$name][$langcode];
         }
-        $field = \Drupal::typedDataManager()->getPropertyInstance($this, $name, $value);
+        $typed_entity = $this->getTypedData();
+        $field = \Drupal::typedDataManager()->getPropertyInstance($typed_entity, $name, $value);
         if ($default) {
           // $this->defaultLangcode might not be set if we are initializing the
           // default language code cache, in which case there is no valid
@@ -479,21 +381,21 @@ public function set($name, $value, $notify = TRUE) {
   /**
    * {@inheritdoc}
    */
-  public function getProperties($include_computed = FALSE) {
-    $properties = array();
+  public function getFields($include_computed = FALSE) {
+    $fields = array();
     foreach ($this->getFieldDefinitions() as $name => $definition) {
       if ($include_computed || !$definition->isComputed()) {
-        $properties[$name] = $this->get($name);
+        $fields[$name] = $this->get($name);
       }
     }
-    return $properties;
+    return $fields;
   }
 
   /**
    * {@inheritdoc}
    */
   public function getIterator() {
-    return new \ArrayIterator($this->getProperties());
+    return new \ArrayIterator($this->getFields());
   }
 
   /**
@@ -523,7 +425,7 @@ public function getFieldDefinitions() {
    */
   public function toArray() {
     $values = array();
-    foreach ($this->getProperties() as $name => $property) {
+    foreach ($this->getFields() as $name => $property) {
       $values[$name] = $property->getValue();
     }
     return $values;
@@ -532,21 +434,6 @@ public function toArray() {
   /**
    * {@inheritdoc}
    */
-  public function isEmpty() {
-    if (!$this->isNew()) {
-      return FALSE;
-    }
-    foreach ($this->getProperties() as $property) {
-      if ($property->getValue() !== NULL) {
-        return FALSE;
-      }
-    }
-    return TRUE;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function access($operation, AccountInterface $account = NULL) {
     if ($operation == 'create') {
       return $this->entityManager()
@@ -635,8 +522,6 @@ public function onChange($name) {
 
   /**
    * {@inheritdoc}
-   *
-   * @return \Drupal\Core\Entity\ContentEntityInterface
    */
   public function getTranslation($langcode) {
     // Ensure we always use the default language code when dealing with the
@@ -723,6 +608,7 @@ protected function initializeTranslation($langcode) {
     // The label is the only entity key that can change based on the language,
     // so unset that in case it is currently set.
     unset($translation->entityKeys['label']);
+    $translation->typedData = NULL;
 
     return $translation;
   }
@@ -817,15 +703,6 @@ public function getTranslationLanguages($include_default = TRUE) {
   }
 
   /**
-   * Overrides Entity::translations().
-   *
-   * @todo: Remove once Entity::translations() gets removed.
-   */
-  public function translations() {
-    return $this->getTranslationLanguages(FALSE);
-  }
-
-  /**
    * Updates the original values with the interim changes.
    */
   public function updateOriginalValues() {
@@ -972,7 +849,7 @@ public function __clone() {
         }
         foreach ($values as $langcode => $items) {
           $this->fields[$name][$langcode] = clone $items;
-          $this->fields[$name][$langcode]->setContext($name, $this);
+          $this->fields[$name][$langcode]->setContext($name, $this->getTypedData());
         }
       }
 
@@ -1006,7 +883,7 @@ public function referencedEntities() {
     $referenced_entities = array();
 
     // Gather a list of referenced entities.
-    foreach ($this->getProperties() as $field_items) {
+    foreach ($this->getFields() as $field_items) {
       foreach ($field_items as $field_item) {
         // Loop over all properties of a field item.
         foreach ($field_item->getProperties(TRUE) as $property) {
diff --git a/core/lib/Drupal/Core/Entity/ContentEntityDatabaseStorage.php b/core/lib/Drupal/Core/Entity/ContentEntityDatabaseStorage.php
index f68a0da..eb1fdb8 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityDatabaseStorage.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityDatabaseStorage.php
@@ -1580,7 +1580,8 @@ protected function readFieldItemsToPurge(FieldDefinitionInterface $field_definit
 
     // Create field item objects and return.
     foreach ($items_by_entity as $revision_id => $values) {
-      $items_by_entity[$revision_id] = \Drupal::typedDataManager()->create($field_definition, $values, $field_definition->getName(), $entities[$revision_id]);
+      $typed_entity = $entities[$revision_id]->getTypedData();
+      $items_by_entity[$revision_id] = \Drupal::typedDataManager()->create($field_definition, $values, $field_definition->getName(), $typed_entity);
     }
     return $items_by_entity;
   }
diff --git a/core/lib/Drupal/Core/Entity/ContentEntityInterface.php b/core/lib/Drupal/Core/Entity/ContentEntityInterface.php
index 249c302..3604879 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityInterface.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityInterface.php
@@ -28,7 +28,7 @@
  *
  * @ingroup entity_api
  */
-interface ContentEntityInterface extends EntityInterface, RevisionableInterface, TranslatableInterface, ComplexDataInterface {
+interface ContentEntityInterface extends EntityInterface, RevisionableInterface, TranslatableInterface {
 
   /**
    * Marks the translation identified by the given language code as existing.
@@ -152,4 +152,66 @@ public function getFieldDefinitions();
    */
   public function toArray();
 
+  /**
+   * Gets a field item list.
+   *
+   * @param $field_name
+   *   The name of the field to get; e.g., 'title' or 'name'.
+   *
+   * @throws \InvalidArgumentException
+   *   If an invalid field name is given.
+   *
+   * @return \Drupal\Core\Field\FieldItemListInterface
+   *   The field item list, containing the field items.
+   */
+  public function get($field_name);
+
+  /**
+   * Sets a field value.
+   *
+   * @param $field_name
+   *   The name of the property to set; e.g., 'title' or 'name'.
+   * @param $value
+   *   The value to set, or NULL to unset the field.
+   * @param bool $notify
+   *   (optional) Whether to notify the entity of the change. Defaults to
+   *   TRUE. If the update stems from the entity, set it to FALSE to avoid
+   *   being notified again.
+   *
+   * @throws \InvalidArgumentException
+   *   If the specified field does not exist.
+   *
+   * @return $this
+   */
+  public function set($field_name, $value, $notify = TRUE);
+
+  /**
+   * Gets an array of field item lists.
+   *
+   * @param bool $include_computed
+   *   If set to TRUE, computed fields are included. Defaults to FALSE.
+   *
+   * @return \Drupal\Core\Field\FieldItemListInterface[]
+   *   An array of field item lists implementing, keyed by field name.
+   */
+  public function getFields($include_computed = FALSE);
+
+  /**
+   * React to changes to a child field.
+   *
+   * Note that this is invoked after any changes have been applied.
+   *
+   * @param $field_name
+   *   The name of the field which is changed.
+   */
+  public function onChange($field_name);
+
+  /**
+   * Validates the currently set values.
+   *
+   * @return \Symfony\Component\Validator\ConstraintViolationListInterface
+   *   A list of constraint violations. If the list is empty, validation
+   *   succeeded.
+   */
+  public function validate();
 }
diff --git a/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php b/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php
index a4849be..ce8f088 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Entity;
 
 use Drupal\Component\Utility\String;
+use Drupal\Core\Field\PrepareCacheInterface;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
 use Drupal\Core\Cache\Cache;
@@ -197,7 +198,7 @@ protected function invokeTranslationHooks(ContentEntityInterface $entity) {
   protected function invokeFieldMethod($method, ContentEntityInterface $entity) {
     foreach (array_keys($entity->getTranslationLanguages()) as $langcode) {
       $translation = $entity->getTranslation($langcode);
-      foreach ($translation->getProperties(TRUE) as $field) {
+      foreach ($translation->getFields(TRUE) as $field) {
         $field->$method();
       }
     }
diff --git a/core/lib/Drupal/Core/Entity/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php
index ba7380a..c9ffc22 100644
--- a/core/lib/Drupal/Core/Entity/Entity.php
+++ b/core/lib/Drupal/Core/Entity/Entity.php
@@ -13,8 +13,6 @@
 use Drupal\Component\Utility\String;
 use Drupal\Component\Utility\Unicode;
 use Drupal\Core\Config\Entity\Exception\ConfigEntityIdLengthException;
-use Drupal\Core\Entity\Exception\AmbiguousEntityClassException;
-use Drupal\Core\Entity\Exception\NoCorrespondingEntityClassException;
 use Drupal\Core\Entity\Exception\UndefinedLinkTemplateException;
 use Drupal\Core\Language\Language;
 use Drupal\Core\Language\LanguageInterface;
@@ -25,7 +23,9 @@
  * Defines a base entity class.
  */
 abstract class Entity implements EntityInterface {
-  use DependencySerializationTrait;
+  use DependencySerializationTrait {
+    __sleep as traitSleep;
+  }
 
   /**
    * The entity type.
@@ -42,6 +42,13 @@
   protected $enforceIsNew;
 
   /**
+   * A typed data object wrapping this entity.
+   *
+   * @var \Drupal\Core\TypedData\ComplexDataInterface
+   */
+  protected $typedData;
+
+  /**
    * Constructs an Entity object.
    *
    * @param array $values
@@ -547,4 +554,23 @@ public function toArray() {
     return array();
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getTypedData() {
+    if (!isset($this->typedData)) {
+      $class = \Drupal::typedDataManager()->getDefinition('entity')['class'];
+      //$this->typedData = $class::createFromEntity($this);
+      return $class::createFromEntity($this);
+    }
+    return $this->typedData;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __sleep() {
+    $this->typedData = NULL;
+    return $this->traitSleep();
+  }
 }
diff --git a/core/lib/Drupal/Core/Entity/EntityInterface.php b/core/lib/Drupal/Core/Entity/EntityInterface.php
index 4399d01..b026948 100644
--- a/core/lib/Drupal/Core/Entity/EntityInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityInterface.php
@@ -359,6 +359,19 @@ public function setOriginalId($id);
   public function toArray();
 
   /**
+   * Returns a typed data object for the entity object.
+   *
+   * The returned typed data objects wraps the entity objects and allows dealing
+   * with entities based on the generic typed data API.
+   *
+   * @return \Drupal\Core\TypedData\ComplexDataInterface
+   *   The typed data object for this entity.
+   *
+   * @see \Drupal\Core\TypedData\TypedDataInterface
+   */
+  public function getTypedData();
+
+  /**
    * The unique cache tag associated with this entity.
    *
    * @return array
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/Deriver/EntityDeriver.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/Deriver/EntityDeriver.php
index dc54e75..0c80fcf 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/DataType/Deriver/EntityDeriver.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/Deriver/EntityDeriver.php
@@ -83,7 +83,6 @@ public function getDerivativeDefinitions($base_plugin_definition) {
     foreach ($this->entityManager->getDefinitions() as $entity_type_id => $entity_type) {
       $this->derivatives[$entity_type_id] = array(
         'label' => $entity_type->getLabel(),
-        'class' => $entity_type->getClass(),
         'constraints' => array('EntityType' => $entity_type_id),
       ) + $base_plugin_definition;
 
@@ -92,7 +91,6 @@ public function getDerivativeDefinitions($base_plugin_definition) {
         if ($bundle !== $entity_type_id) {
           $this->derivatives[$entity_type_id . ':' . $bundle] = array(
             'label' => $bundle_info['label'],
-            'class' => $entity_type->getClass(),
             'constraints' => array(
               'EntityType' => $entity_type_id,
               'Bundle' => $bundle,
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/Entity.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/Entity.php
index 5755c51..7ba95a0 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/DataType/Entity.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/Entity.php
@@ -7,11 +7,21 @@
 
 namespace Drupal\Core\Entity\Plugin\DataType;
 
+use Drupal\Component\Utility\String;
+use Drupal\Core\Entity\ContentEntityInterface;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\TypedData\EntityDataDefinition;
+use Drupal\Core\TypedData\ComplexDataInterface;
+use Drupal\Core\TypedData\Exception\MissingDataException;
+use Drupal\Core\TypedData\TypedData;
+
 /**
- * Defines the base plugin for deriving data types for entity types.
+ * Defines the "entity" data type.
  *
- * Note that the class only registers the plugin, and is actually never used.
- * \Drupal\Core\Entity\Entity is available for use as base class.
+ * Instances of this class wrap entity objects and allow to deal with entities
+ * based upon the typed data API.
+ * In addition to the "entity" data type, there is derivative which exposes
+ * "entity:$entity_type" and "entity:$entity_type:$bundle" data types.
  *
  * @DataType(
  *   id = "entity",
@@ -21,6 +31,144 @@
  *   definition_class = "\Drupal\Core\Entity\TypedData\EntityDataDefinition"
  * )
  */
-abstract class Entity {
+class Entity extends TypedData implements \IteratorAggregate, ComplexDataInterface {
+
+  /**
+   * The wrapped entity object.
+   *
+   * @var \Drupal\Core\Entity\EntityInterface|null
+   */
+  protected $entity;
+
+  /**
+   * Creates an instance wrapping the given entity.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface|null $entity
+   *   The entity object to wrap.
+   *
+   * @return static
+   */
+  public static function createFromEntity(EntityInterface $entity) {
+    $definition = EntityDataDefinition::create()
+      ->setEntityTypeId($entity->getEntityTypeId())
+      ->setBundles([ $entity->bundle() ]);
+    $instance = new static($definition);
+    $instance->setValue($entity);
+    return $instance;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getValue() {
+    return $this->entity;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setValue($entity, $notify = TRUE) {
+    $this->entity = $entity;
+    // Notify the parent of any changes.
+    if ($notify && isset($this->parent)) {
+      $this->parent->onChange($this->name);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function get($property_name) {
+    if (isset($this->entity) && $this->entity instanceof ContentEntityInterface) {
+      return $this->entity->get($property_name);
+    }
+    // @todo: Add support for config entities.
+    throw new MissingDataException(String::format('Unable to get property @name as no entity has been provided.', array('@name' => $property_name)));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function set($property_name, $value, $notify = TRUE) {
+    if (isset($this->entity) && $this->entity instanceof ContentEntityInterface) {
+      $property = $this->entity->set($property_name, $value);
+      // Notify the parent of any changes.
+      if ($notify && isset($this->parent)) {
+        $this->parent->onChange($this->name);
+      }
+      return $property;
+    }
+    // @todo: Add support for config entities.
+    throw new MissingDataException(String::format('Unable to set property @name as no entity has been provided.', array('@name' => $property_name)));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getProperties($include_computed = FALSE) {
+    if (isset($this->entity)) {
+      return $this->entity->getFields($include_computed);
+    }
+    throw new MissingDataException(String::format('Unable to get properties as no entity has been provided.'));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function toArray() {
+    if (isset($this->entity)) {
+      return $this->entity->toArray();
+    }
+    throw new MissingDataException(String::format('Unable to get property values as no entity has been provided.'));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isEmpty() {
+    return isset($this->entity);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function onChange($property_name) {
+    if (isset($this->entity)) {
+      // Let the entity know of any changes.
+      $this->entity->onChange($property_name);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDataDefinition() {
+    return $this->definition;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getString() {
+    return isset($this->entity) ? $this->entity->label() : '';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function applyDefaultValue($notify = TRUE) {
+    // Apply the default value of all properties.
+    foreach ($this->getProperties() as $property) {
+      $property->applyDefaultValue(FALSE);
+    }
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIterator() {
+    return isset($this->entity) ? $this->entity->getIterator() : new \ArrayIterator([]);
+  }
 
 }
diff --git a/core/lib/Drupal/Core/Entity/TypedData/EntityDataDefinition.php b/core/lib/Drupal/Core/Entity/TypedData/EntityDataDefinition.php
index c2268c8..137da72 100644
--- a/core/lib/Drupal/Core/Entity/TypedData/EntityDataDefinition.php
+++ b/core/lib/Drupal/Core/Entity/TypedData/EntityDataDefinition.php
@@ -59,7 +59,7 @@ public function getPropertyDefinitions() {
       if ($entity_type_id = $this->getEntityTypeId()) {
         // Return an empty array for entity types that don't support typed data.
         $entity_type_class = \Drupal::entityManager()->getDefinition($entity_type_id)->getClass();
-        if (!in_array('Drupal\Core\TypedData\TypedDataInterface', class_implements($entity_type_class))) {
+        if (!in_array('Drupal\Core\Entity\ContentEntityInterface', class_implements($entity_type_class))) {
           $this->propertyDefinitions = array();
         }
         else {
diff --git a/core/lib/Drupal/Core/Field/FieldItemInterface.php b/core/lib/Drupal/Core/Field/FieldItemInterface.php
index 8577a04..8e0dbc6 100644
--- a/core/lib/Drupal/Core/Field/FieldItemInterface.php
+++ b/core/lib/Drupal/Core/Field/FieldItemInterface.php
@@ -90,7 +90,7 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
   /**
    * Gets the entity that field belongs to.
    *
-   * @return \Drupal\Core\Entity\EntityInterface
+   * @return \Drupal\Core\Entity\ContentEntityInterface
    *   The entity object.
    */
   public function getEntity();
diff --git a/core/lib/Drupal/Core/Field/FieldItemList.php b/core/lib/Drupal/Core/Field/FieldItemList.php
index 7f0890d..ab275e2 100644
--- a/core/lib/Drupal/Core/Field/FieldItemList.php
+++ b/core/lib/Drupal/Core/Field/FieldItemList.php
@@ -41,10 +41,18 @@ class FieldItemList extends ItemList implements FieldItemListInterface {
   protected $langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED;
 
   /**
+   * The parent entity.
+   *
+   * @var \Drupal\Core\Entity\ContentEntityInterface;
+   */
+  protected $entity;
+
+  /**
    * {@inheritdoc}
    */
   public function __construct(DataDefinitionInterface $definition, $name = NULL, TypedDataInterface $parent = NULL) {
-    parent::__construct($definition, $name, $parent);
+    $this->entity = isset($parent) ? $parent->getValue() : NULL;
+    parent::__construct($definition, $name, NULL);
     // Always initialize one empty item as most times a value for at least one
     // item will be present. That way prototypes created by
     // \Drupal\Core\TypedData\TypedDataManager::getPropertyInstance() will
@@ -56,7 +64,22 @@ public function __construct(DataDefinitionInterface $definition, $name = NULL, T
    * {@inheritdoc}
    */
   public function getEntity() {
-    return $this->getParent();
+    return $this->entity;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getParent() {
+    return $this->parent->getTypedData();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setContext($name = NULL, TypedDataInterface $parent = NULL) {
+    $this->entity = isset($parent) ? $parent->getValue() : NULL;
+    $this->name = $name;
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Plugin/Context/Context.php b/core/lib/Drupal/Core/Plugin/Context/Context.php
index 0366b71..a0ad01f 100644
--- a/core/lib/Drupal/Core/Plugin/Context/Context.php
+++ b/core/lib/Drupal/Core/Plugin/Context/Context.php
@@ -10,7 +10,6 @@
 use Drupal\Component\Plugin\Context\Context as ComponentContext;
 use Drupal\Component\Plugin\Exception\ContextException;
 use Drupal\Component\Utility\String;
-use Drupal\Core\Entity\ContentEntityInterface;
 use Drupal\Core\TypedData\TypedDataInterface;
 use Drupal\Core\TypedData\TypedDataTrait;
 
@@ -47,11 +46,6 @@ public function getContextValue() {
       }
       return NULL;
     }
-    // Special case entities.
-    // @todo: Remove once entities do not implemented TypedDataInterface.
-    if ($this->contextData instanceof ContentEntityInterface) {
-      return $this->contextData;
-    }
     return $this->contextData->getValue();
   }
 
diff --git a/core/lib/Drupal/Core/TypedData/ComplexDataInterface.php b/core/lib/Drupal/Core/TypedData/ComplexDataInterface.php
index 923090e..7b8895a 100644
--- a/core/lib/Drupal/Core/TypedData/ComplexDataInterface.php
+++ b/core/lib/Drupal/Core/TypedData/ComplexDataInterface.php
@@ -33,6 +33,8 @@
    *
    * @throws \InvalidArgumentException
    *   If an invalid property name is given.
+   * @throws \Drupal\Core\TypedData\MissingDataException
+   *   If the complex data structure is unset and no property can be created.
    *
    * @return \Drupal\Core\TypedData\TypedDataInterface
    *   The property object.
@@ -53,6 +55,8 @@ public function get($property_name);
    *
    * @throws \InvalidArgumentException
    *   If the specified property does not exist.
+   * @throws \Drupal\Core\TypedData\MissingDataException
+   *   If the complex data structure is unset and no property can be set.
    *
    * @return \Drupal\Core\TypedData\TypedDataInterface
    *   The property object.
@@ -65,6 +69,9 @@ public function set($property_name, $value, $notify = TRUE);
    * @param bool $include_computed
    *   If set to TRUE, computed properties are included. Defaults to FALSE.
    *
+   * @throws \Drupal\Core\TypedData\MissingDataException
+   *   If the complex data structure is unset and no property can be created.
+   *
    * @return \Drupal\Core\TypedData\TypedDataInterface[]
    *   An array of property objects implementing the TypedDataInterface, keyed
    *   by property name.
@@ -77,6 +84,9 @@ public function getProperties($include_computed = FALSE);
    * Gets an array of plain property values including all not-computed
    * properties.
    *
+   * @throws \Drupal\Core\TypedData\MissingDataException
+   *   If the complex data structure is unset and no property can be created.
+   *
    * @return array
    *   An array of property values, keyed by property name.
    */
diff --git a/core/lib/Drupal/Core/TypedData/DataDefinitionException.php b/core/lib/Drupal/Core/TypedData/DataDefinitionException.php
deleted file mode 100644
index 2a23315..0000000
--- a/core/lib/Drupal/Core/TypedData/DataDefinitionException.php
+++ /dev/null
@@ -1,15 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\TypedData\MissingContextException.
- */
-
-namespace Drupal\Core\TypedData;
-
-/**
- * Exception thrown when a data definition lacks required information.
- */
-class DataDefinitionException extends \Exception {
-
-}
diff --git a/core/lib/Drupal/Core/TypedData/Exception/MissingDataException.php b/core/lib/Drupal/Core/TypedData/Exception/MissingDataException.php
new file mode 100644
index 0000000..f2ef0e9
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/Exception/MissingDataException.php
@@ -0,0 +1,13 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\MissingDataException.
+ */
+
+namespace Drupal\Core\TypedData\Exception;
+
+/**
+ * Exception thrown when an operation misses a data value; i.e., it is unset.
+ */
+class MissingDataException extends \Exception {}
diff --git a/core/lib/Drupal/Core/TypedData/Exception/ReadOnlyException.php b/core/lib/Drupal/Core/TypedData/Exception/ReadOnlyException.php
new file mode 100644
index 0000000..d3e0371
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/Exception/ReadOnlyException.php
@@ -0,0 +1,13 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\ReadOnlyException.
+ */
+
+namespace Drupal\Core\TypedData\Exception;
+
+/**
+ * Exception thrown when trying to write or set ready-only data.
+ */
+class ReadOnlyException extends \Exception {}
diff --git a/core/lib/Drupal/Core/TypedData/ListInterface.php b/core/lib/Drupal/Core/TypedData/ListInterface.php
index bf70d6f..438dddd 100644
--- a/core/lib/Drupal/Core/TypedData/ListInterface.php
+++ b/core/lib/Drupal/Core/TypedData/ListInterface.php
@@ -54,6 +54,9 @@ public function onChange($delta);
    * @param int $index
    *   Index of the item to return.
    *
+   * @throws \Drupal\Core\TypedData\MissingDataException
+   *   If the complex data structure is unset and no item can be created.
+   *
    * @return \Drupal\Core\TypedData\TypedDataInterface
    *   The item at the specified position in this list. An empty item is created
    *   if it does not exist yet.
@@ -68,6 +71,9 @@ public function get($index);
    * @param mixed
    *   Item to be stored at the specified position.
    *
+   * @throws \Drupal\Core\TypedData\MissingDataException
+   *   If the complex data structure is unset and no item can be set.
+   *
    * @return static
    *   Returns the list.
    */
@@ -76,6 +82,9 @@ public function set($index, $item);
   /**
    * Returns the first item in this list.
    *
+   * @throws \Drupal\Core\TypedData\MissingDataException
+   *   If the complex data structure is unset and no item can be created.
+   *
    * @return \Drupal\Core\TypedData\TypedDataInterface
    *   The first item in this list.
    */
diff --git a/core/lib/Drupal/Core/TypedData/MissingContextException.php b/core/lib/Drupal/Core/TypedData/MissingContextException.php
deleted file mode 100644
index b4a7c8e..0000000
--- a/core/lib/Drupal/Core/TypedData/MissingContextException.php
+++ /dev/null
@@ -1,13 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\TypedData\MissingContextException.
- */
-
-namespace Drupal\Core\TypedData;
-
-/**
- * Exception thrown when data wrappers miss contextual information.
- */
-class MissingContextException extends \Exception {}
diff --git a/core/lib/Drupal/Core/TypedData/ReadOnlyException.php b/core/lib/Drupal/Core/TypedData/ReadOnlyException.php
deleted file mode 100644
index 2486a16..0000000
--- a/core/lib/Drupal/Core/TypedData/ReadOnlyException.php
+++ /dev/null
@@ -1,13 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\TypedData\ReadOnlyException.
- */
-
-namespace Drupal\Core\TypedData;
-
-/**
- * Exception thrown when trying to write or set ready-only data.
- */
-class ReadOnlyException extends \Exception {}
diff --git a/core/lib/Drupal/Core/TypedData/TranslatableInterface.php b/core/lib/Drupal/Core/TypedData/TranslatableInterface.php
index 4b028ff..df72555 100644
--- a/core/lib/Drupal/Core/TypedData/TranslatableInterface.php
+++ b/core/lib/Drupal/Core/TypedData/TranslatableInterface.php
@@ -44,7 +44,7 @@ public function getTranslationLanguages($include_default = TRUE);
    *   LanguageInterface::LANGCODE_DEFAULT
    *   to get the data in default language.
    *
-   * @return \Drupal\Core\TypedData\TypedDataInterface
+   * @return $this
    *   A typed data object for the translated data.
    */
   public function getTranslation($langcode);
@@ -52,7 +52,7 @@ public function getTranslation($langcode);
   /**
    * Returns the translatable object referring to the original language.
    *
-   * @return \Drupal\Core\TypedData\TranslatableInterface
+   * @return $this
    *   The translation object referring to the original language.
    */
   public function getUntranslated();
@@ -77,7 +77,7 @@ public function hasTranslation($langcode);
    *   (optional) An array of initial values to be assigned to the translatable
    *   fields. Defaults to none.
    *
-   * @return \Drupal\Core\TypedData\TranslatableInterface
+   * @return $this
    */
   public function addTranslation($langcode, array $values = array());
 
diff --git a/core/lib/Drupal/Core/TypedData/TypedData.php b/core/lib/Drupal/Core/TypedData/TypedData.php
index 1ad3fb8..b0f614c 100644
--- a/core/lib/Drupal/Core/TypedData/TypedData.php
+++ b/core/lib/Drupal/Core/TypedData/TypedData.php
@@ -44,6 +44,13 @@
   protected $parent;
 
   /**
+   * {@inheritdoc}
+   */
+  public static function createInstance($definition, $name = NULL, TypedDataInterface $parent = NULL) {
+    return new static($definition, $name, $parent);
+  }
+
+  /**
    * Constructs a TypedData object given its definition and context.
    *
    * @param \Drupal\Core\TypedData\DataDefinitionInterface $definition
diff --git a/core/lib/Drupal/Core/TypedData/TypedDataInterface.php b/core/lib/Drupal/Core/TypedData/TypedDataInterface.php
index a7eb8a2..a54b9be 100644
--- a/core/lib/Drupal/Core/TypedData/TypedDataInterface.php
+++ b/core/lib/Drupal/Core/TypedData/TypedDataInterface.php
@@ -19,6 +19,26 @@
 interface TypedDataInterface {
 
   /**
+   * Constructs a TypedData object given its definition and context.
+   *
+   * @param \Drupal\Core\TypedData\DataDefinitionInterface $definition
+   *   The data definition.
+   * @param string $name
+   *   (optional) The name of the created property, or NULL if it is the root
+   *   of a typed data tree. Defaults to NULL.
+   * @param \Drupal\Core\TypedData\TypedDataInterface $parent
+   *   (optional) The parent object of the data property, or NULL if it is the
+   *   root of a typed data tree. Defaults to NULL.
+   *
+   * @see \Drupal\Core\TypedData\TypedDataManager::create()
+   *
+   * @todo When \Drupal\Core\Config\TypedConfigManager has been fixed to use
+   *   class-based definitions, type-hint $definition to
+   *   DataDefinitionInterface. https://drupal.org/node/1928868
+   */
+  public static function createInstance($definition, $name = NULL, TypedDataInterface $parent = NULL);
+
+  /**
    * Gets the data definition.
    *
    * @return \Drupal\Core\TypedData\DataDefinitionInterface
@@ -46,7 +66,7 @@ public function getValue();
    *
    * @throws \InvalidArgumentException
    *   If the value input is inappropriate.
-   * @throws \Drupal\Core\TypedData\ReadOnlyException
+   * @throws \Drupal\Core\TypedData\Exception\ReadOnlyException
    *   If the data is read-only.
    */
   public function setValue($value, $notify = TRUE);
diff --git a/core/lib/Drupal/Core/TypedData/TypedDataManager.php b/core/lib/Drupal/Core/TypedData/TypedDataManager.php
index c9afe86..3807675 100644
--- a/core/lib/Drupal/Core/TypedData/TypedDataManager.php
+++ b/core/lib/Drupal/Core/TypedData/TypedDataManager.php
@@ -95,7 +95,7 @@ public function createInstance($data_type, array $configuration = array()) {
     if (!isset($class)) {
       throw new PluginException(sprintf('The plugin (%s) did not specify an instance class.', $data_type));
     }
-    return new $class($data_definition, $configuration['name'], $configuration['parent']);
+    return $class::createInstance($data_definition, $configuration['name'], $configuration['parent']);
   }
 
   /**
diff --git a/core/modules/hal/src/Normalizer/ContentEntityNormalizer.php b/core/modules/hal/src/Normalizer/ContentEntityNormalizer.php
index d433656..0f67644 100644
--- a/core/modules/hal/src/Normalizer/ContentEntityNormalizer.php
+++ b/core/modules/hal/src/Normalizer/ContentEntityNormalizer.php
@@ -86,7 +86,7 @@ public function normalize($entity, $format = NULL, array $context = array()) {
       }
     }
     else {
-      $fields = $entity->getProperties();
+      $fields = $entity->getFields();
     }
     // Ignore the entity ID and revision ID.
     $exclude = array($entity->getEntityType()->getKey('id'), $entity->getEntityType()->getKey('revision'));
diff --git a/core/modules/hal/src/Normalizer/EntityReferenceItemNormalizer.php b/core/modules/hal/src/Normalizer/EntityReferenceItemNormalizer.php
index d5ba85a..4673457 100644
--- a/core/modules/hal/src/Normalizer/EntityReferenceItemNormalizer.php
+++ b/core/modules/hal/src/Normalizer/EntityReferenceItemNormalizer.php
@@ -73,6 +73,10 @@ public function normalize($field_item, $format = NULL, array $context = array())
 
     // Normalize the target entity.
     $embedded = $this->serializer->normalize($target_entity, $format, $context);
+    // @todo Config entities currently can not be serialized, skip them.
+    if (empty($embedded['_links']['self'])) {
+      return array();
+    }
     $link = $embedded['_links']['self'];
     // If the field is translatable, add the langcode to the link relation
     // object. This does not indicate the language of the target entity.
diff --git a/core/modules/serialization/tests/src/Normalizer/EntityNormalizerTest.php b/core/modules/serialization/tests/src/Normalizer/EntityNormalizerTest.php
index 4d6a409..45439c0 100644
--- a/core/modules/serialization/tests/src/Normalizer/EntityNormalizerTest.php
+++ b/core/modules/serialization/tests/src/Normalizer/EntityNormalizerTest.php
@@ -61,10 +61,10 @@ public function testNormalize() {
 
     $content_entity = $this->getMockBuilder('Drupal\Core\Entity\ContentEntityBase')
       ->disableOriginalConstructor()
-      ->setMethods(array('getProperties'))
+      ->setMethods(array('getFields'))
       ->getMockForAbstractClass();
     $content_entity->expects($this->once())
-      ->method('getProperties')
+      ->method('getFields')
       ->will($this->returnValue($definitions));
 
     $serializer = $this->getMockBuilder('Symfony\Component\Serializer\Serializer')
diff --git a/core/modules/system/src/Tests/Entity/EntityFieldTest.php b/core/modules/system/src/Tests/Entity/EntityFieldTest.php
index 2166b4c..9529b9b 100644
--- a/core/modules/system/src/Tests/Entity/EntityFieldTest.php
+++ b/core/modules/system/src/Tests/Entity/EntityFieldTest.php
@@ -414,27 +414,28 @@ protected function checkIntrospection($entity_type) {
     $this->assertEqual($textfield_properties['processed']->getDataType(), 'string', $entity_type .': String processed property of the test-text field found.');
 
     // Make sure provided contextual information is right.
-    $this->assertIdentical($entity->getRoot(), $entity, 'Entity is root object.');
-    $this->assertEqual($entity->getPropertyPath(), '');
-    $this->assertEqual($entity->getName(), '');
-    $this->assertEqual($entity->getParent(), NULL);
+    $typed_entity = $entity->getTypedData();
+    $this->assertIdentical($typed_entity->getRoot(), $typed_entity, 'Entity is root object.');
+    $this->assertEqual($typed_entity->getPropertyPath(), '');
+    $this->assertEqual($typed_entity->getName(), '');
+    $this->assertEqual($typed_entity->getParent(), NULL);
 
     $field = $entity->user_id;
-    $this->assertIdentical($field->getRoot(), $entity, 'Entity is root object.');
+    $this->assertIdentical($field->getRoot()->getEntity(), $entity, 'Entity is root object.');
     $this->assertIdentical($field->getEntity(), $entity, 'getEntity() returns the entity.');
     $this->assertEqual($field->getPropertyPath(), 'user_id');
     $this->assertEqual($field->getName(), 'user_id');
-    $this->assertIdentical($field->getParent(), $entity, 'Parent object matches.');
+    $this->assertIdentical($field->getParent()->getEntity(), $entity, 'Parent object matches.');
 
     $field_item = $field[0];
-    $this->assertIdentical($field_item->getRoot(), $entity, 'Entity is root object.');
+    $this->assertIdentical($field_item->getRoot()->getEntity(), $entity, 'Entity is root object.');
     $this->assertIdentical($field_item->getEntity(), $entity, 'getEntity() returns the entity.');
     $this->assertEqual($field_item->getPropertyPath(), 'user_id.0');
     $this->assertEqual($field_item->getName(), '0');
     $this->assertIdentical($field_item->getParent(), $field, 'Parent object matches.');
 
     $item_value = $field_item->get('entity');
-    $this->assertIdentical($item_value->getRoot(), $entity, 'Entity is root object.');
+    $this->assertIdentical($item_value->getRoot()->getEntity(), $entity, 'Entity is root object.');
     $this->assertEqual($item_value->getPropertyPath(), 'user_id.0.entity');
     $this->assertEqual($item_value->getName(), 'entity');
     $this->assertIdentical($item_value->getParent(), $field_item, 'Parent object matches.');
@@ -474,9 +475,9 @@ protected function assertIterator($entity_type) {
       }
     }
 
-    $properties = $entity->getProperties();
-    $this->assertEqual(array_keys($properties), array_keys($entity->getDataDefinition()->getPropertyDefinitions()), format_string('%entity_type: All properties returned.', array('%entity_type' => $entity_type)));
-    $this->assertEqual($properties, iterator_to_array($entity->getIterator()), format_string('%entity_type: Entity iterator iterates over all properties.', array('%entity_type' => $entity_type)));
+    $fields = $entity->getFields();
+    $this->assertEqual(array_keys($fields), array_keys($entity->getDataDefinition()->getPropertyDefinitions()), format_string('%entity_type: All fields returned.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($fields, iterator_to_array($entity->getIterator()), format_string('%entity_type: Entity iterator iterates over all fields.', array('%entity_type' => $entity_type)));
   }
 
   /**
@@ -502,7 +503,7 @@ protected function assertDataStructureInterfaces($entity_type) {
     // contained properties and getting all contained strings, limited by a
     // certain depth.
     $strings = array();
-    $this->getContainedStrings($entity, 0, $strings);
+    $this->getContainedStrings($entity->getTypedData(), 0, $strings);
 
     // @todo: Once the user entity has defined properties this should contain
     // the user name and other user entity strings as well.
diff --git a/core/modules/system/src/Tests/Entity/EntityUUIDTest.php b/core/modules/system/src/Tests/Entity/EntityUUIDTest.php
index 39bfa70..5f3b6e1 100644
--- a/core/modules/system/src/Tests/Entity/EntityUUIDTest.php
+++ b/core/modules/system/src/Tests/Entity/EntityUUIDTest.php
@@ -73,7 +73,7 @@ protected function assertCRUD($entity_type) {
 
     // Creating a duplicate needs to result in a new UUID.
     $entity_duplicate = $entity->createDuplicate();
-    foreach ($entity->getProperties() as $property => $value) {
+    foreach ($entity->getFields() as $property => $value) {
       switch($property) {
         case 'uuid':
           $this->assertNotNull($entity_duplicate->uuid());
diff --git a/core/modules/system/src/Tests/Entity/EntityValidationTest.php b/core/modules/system/src/Tests/Entity/EntityValidationTest.php
index 73f0fd9..9e8ddd5 100644
--- a/core/modules/system/src/Tests/Entity/EntityValidationTest.php
+++ b/core/modules/system/src/Tests/Entity/EntityValidationTest.php
@@ -133,7 +133,7 @@ protected function checkValidation($entity_type) {
 
     // Make sure the information provided by a violation is correct.
     $violation = $violations[0];
-    $this->assertEqual($violation->getRoot(), $test_entity, 'Violation root is entity.');
+    $this->assertEqual($violation->getRoot()->getEntity(), $test_entity, 'Violation root is entity.');
     $this->assertEqual($violation->getPropertyPath(), 'name.0.value', 'Violation property path is correct.');
     $this->assertEqual($violation->getInvalidValue(), $test_entity->name->value, 'Violation contains invalid value.');
 
@@ -151,7 +151,7 @@ protected function checkValidation($entity_type) {
 
     // Make sure the information provided by a violation is correct.
     $violation = $violations[0];
-    $this->assertEqual($violation->getRoot(), $test_entity, 'Violation root is entity.');
+    $this->assertEqual($violation->getRoot()->getEntity(), $test_entity, 'Violation root is entity.');
     $this->assertEqual($violation->getPropertyPath(), 'field_test_text.0.format', 'Violation property path is correct.');
     $this->assertEqual($violation->getInvalidValue(), $test_entity->field_test_text->format, 'Violation contains invalid value.');
   }
diff --git a/core/modules/user/src/Plugin/Validation/Constraint/UserUniqueValidator.php b/core/modules/user/src/Plugin/Validation/Constraint/UserUniqueValidator.php
index b98408a..92ff5cc 100644
--- a/core/modules/user/src/Plugin/Validation/Constraint/UserUniqueValidator.php
+++ b/core/modules/user/src/Plugin/Validation/Constraint/UserUniqueValidator.php
@@ -20,7 +20,7 @@ class UserUniqueValidator extends ConstraintValidator {
    */
   public function validate($value, Constraint $constraint) {
     $field = $this->context->getMetadata()->getTypedData()->getParent();
-    $uid = $field->getParent()->id();
+    $uid = $field->getEntity()->id();
 
     $value_taken = (bool) \Drupal::entityQuery('user')
       // The UID could be NULL, so we cast it to 0 in that case.
diff --git a/core/modules/views_ui/src/ViewUI.php b/core/modules/views_ui/src/ViewUI.php
index 64f8cae..9e8f8e6 100644
--- a/core/modules/views_ui/src/ViewUI.php
+++ b/core/modules/views_ui/src/ViewUI.php
@@ -1125,4 +1125,10 @@ public function getListCacheTags() {
     $this->storage->getListCacheTags();
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getTypedData() {
+    $this->storage->getTypedData();
+  }
 }
diff --git a/core/tests/Drupal/Tests/Core/Entity/ContentEntityBaseUnitTest.php b/core/tests/Drupal/Tests/Core/Entity/ContentEntityBaseUnitTest.php
index dfd6b47..0ab7001 100644
--- a/core/tests/Drupal/Tests/Core/Entity/ContentEntityBaseUnitTest.php
+++ b/core/tests/Drupal/Tests/Core/Entity/ContentEntityBaseUnitTest.php
@@ -9,7 +9,6 @@
 
 use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Core\Field\BaseFieldDefinition;
-use Drupal\Core\Field\FieldItemBase;
 use Drupal\Tests\UnitTestCase;
 use Drupal\Core\Language\Language;
 
@@ -209,8 +208,13 @@ public function testIsNewRevision() {
       ->getMockForAbstractClass();
 
     $this->typedDataManager->expects($this->any())
+      ->method('getDefinition')
+      ->with('entity')
+      ->will($this->returnValue(['class' => '\Drupal\Core\Entity\Plugin\DataType\Entity']));
+
+    $this->typedDataManager->expects($this->any())
       ->method('getPropertyInstance')
-      ->with($this->entity, 'revision_id', NULL)
+      ->with($this->entity->getTypedData(), 'revision_id', NULL)
       ->will($this->returnValue($field_item_list));
 
     $this->fieldDefinitions['revision_id']->getItemDefinition()->setClass(get_class($field_item));
@@ -269,23 +273,6 @@ public function testPreSaveRevision() {
   }
 
   /**
-   * @covers ::getString
-   */
-  public function testGetString() {
-    $label = $this->randomMachineName();
-    /** @var \Drupal\Core\Entity\ContentEntityBase|\PHPUnit_Framework_MockObject_MockObject $entity */
-    $entity = $this->getMockBuilder('\Drupal\Core\Entity\ContentEntityBase')
-      ->setMethods(array('label'))
-      ->disableOriginalConstructor()
-      ->getMockForAbstractClass();
-    $entity->expects($this->once())
-      ->method('label')
-      ->will($this->returnValue($label));
-
-    $this->assertSame($label, $entity->getString());
-  }
-
-  /**
    * @covers ::validate
    */
   public function testValidate() {
@@ -299,11 +286,11 @@ public function testValidate() {
     $non_empty_violation_list->add($violation);
     $validator->expects($this->at(0))
       ->method('validate')
-      ->with($this->entity)
+      ->with($this->entity->getTypedData())
       ->will($this->returnValue($empty_violation_list));
     $validator->expects($this->at(1))
       ->method('validate')
-      ->with($this->entity)
+      ->with($this->entity->getTypedData())
       ->will($this->returnValue($non_empty_violation_list));
     $this->typedDataManager->expects($this->exactly(2))
       ->method('getValidator')
@@ -358,6 +345,7 @@ public function testSetContext() {
   }
 
   /**
+>>>>>>> 8.0.x
    * @covers ::bundle
    */
   public function testBundle() {
