diff --git a/core/lib/Drupal/Core/Entity/ContentEntityBase.php b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
index 2ece2b5..307794f 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityBase.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Utility\String;
 use Drupal\Core\Entity\Plugin\DataType\EntityReference;
+use Drupal\Core\Entity\Plugin\DataType\EntityTypedDataWrapper;
 use Drupal\Core\Entity\TypedData\EntityDataDefinition;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Session\AccountInterface;
@@ -263,87 +264,9 @@ public function getDataDefinition() {
   /**
    * {@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.
+    // @todo: Add the typed data manager as proper dependency.
+    return \Drupal::typedDataManager()->getValidator()->validate(new EntityTypedDataWrapper($this));
   }
 
   /**
@@ -404,11 +327,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];
   }
 
   /**
@@ -443,7 +366,8 @@ protected function getTranslatedField($name, $langcode) {
         if (isset($this->values[$name][$langcode])) {
           $value = $this->values[$name][$langcode];
         }
-        $field = \Drupal::typedDataManager()->getPropertyInstance($this, $name, $value);
+        $wrapper = new EntityTypedDataWrapper($this);
+        $field = \Drupal::typedDataManager()->getPropertyInstance($wrapper, $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
@@ -472,21 +396,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());
   }
 
   /**
@@ -516,7 +440,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;
@@ -525,21 +449,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()
@@ -623,8 +532,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
@@ -805,15 +712,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() {
@@ -960,7 +858,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, new EntityTypedDataWrapper($this));
         }
       }
 
@@ -994,7 +892,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/ContentEntityInterface.php b/core/lib/Drupal/Core/Entity/ContentEntityInterface.php
index f07936c..12d7ad8 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.
@@ -137,4 +137,58 @@ 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);
+
 }
diff --git a/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php b/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php
index 29c1de9..695df8c 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php
@@ -8,6 +8,8 @@
 namespace Drupal\Core\Entity;
 
 use Drupal\Component\Utility\String;
+use Drupal\Core\Entity\Plugin\DataType\EntityTypedDataWrapper;
+use Drupal\Core\Field\PrepareCacheInterface;
 use Drupal\Core\Cache\Cache;
 use Drupal\field\FieldConfigInterface;
 use Drupal\field\FieldInstanceConfigInterface;
@@ -314,7 +316,7 @@ public function onBundleDelete($bundle) { }
    */
   public function onFieldItemsPurge(EntityInterface $entity, FieldInstanceConfigInterface $instance) {
     if ($values = $this->readFieldItemsToPurge($entity, $instance)) {
-      $items = \Drupal::typedDataManager()->create($instance, $values, $instance->getName(), $entity);
+      $items = \Drupal::typedDataManager()->create($instance, $values, $instance->getName(), new EntityTypedDataWrapper($entity));
       $items->delete();
     }
     $this->purgeFieldItems($entity, $instance);
@@ -385,7 +387,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/Plugin/DataType/Entity.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/Entity.php
deleted file mode 100644
index 785cde9..0000000
--- a/core/lib/Drupal/Core/Entity/Plugin/DataType/Entity.php
+++ /dev/null
@@ -1,26 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\Entity\Plugin\DataType\Entity.
- */
-
-namespace Drupal\Core\Entity\Plugin\DataType;
-
-/**
- * Defines the base plugin for deriving data types for entity types.
- *
- * Note that the class only registers the plugin, and is actually never used.
- * \Drupal\Core\Entity\Entity is available for use as base class.
- *
- * @DataType(
- *   id = "entity",
- *   label = @Translation("Entity"),
- *   description = @Translation("All kind of entities, e.g. nodes, comments or users."),
- *   derivative = "\Drupal\Core\Entity\Plugin\DataType\Deriver\EntityDeriver",
- *   definition_class = "\Drupal\Core\Entity\TypedData\EntityDataDefinition"
- * )
- */
-abstract class Entity {
-
-}
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityTypedDataWrapper.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityTypedDataWrapper.php
new file mode 100644
index 0000000..247230e
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityTypedDataWrapper.php
@@ -0,0 +1,187 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\Plugin\DataType\EntityTypedDataWrapper.
+ */
+
+namespace Drupal\Core\Entity\Plugin\DataType;
+use Drupal\Core\Entity\ContentEntityInterface;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\TypedData\ComplexDataInterface;
+use Drupal\Core\TypedData\DataDefinitionInterface;
+use Drupal\Core\TypedData\TypedDataInterface;
+
+/**
+ * Defines the base plugin for deriving data types for entity types.
+ *
+ * Note that the class only registers the plugin, and is actually never used.
+ * \Drupal\Core\Entity\Entity is available for use as base class.
+ *
+ * @DataType(
+ *   id = "entity",
+ *   label = @Translation("Entity"),
+ *   description = @Translation("All kind of entities, e.g. nodes, comments or users."),
+ *   derivative = "\Drupal\Core\Entity\Plugin\DataType\Deriver\EntityDeriver",
+ *   definition_class = "\Drupal\Core\Entity\TypedData\EntityDataDefinition"
+ * )
+ */
+class EntityTypedDataWrapper implements \IteratorAggregate, ComplexDataInterface {
+
+  /**
+   * @var \Drupal\Core\Entity\ContentEntityInterface
+   */
+  protected $entity;
+
+  public function __construct(ContentEntityInterface $entity) {
+    if ($entity instanceof DataDefinitionInterface) {
+      debug(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS));
+    }
+    $this->entity = $entity;
+  }
+
+  public function getEntity() {
+    return $this->entity;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function get($property_name) {
+    $this->entity->get($property_name);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function set($property_name, $value, $notify = TRUE) {
+    return $this->entity->set($property_name, $value, $notify);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getProperties($include_computed = FALSE) {
+    return $this->entity->getFields($include_computed);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function toArray() {
+    return $this->entity->toArray();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setPropertyValues($values) {
+    // TODO: Implement setPropertyValues() method.
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isEmpty() {
+    // TODO: Implement isEmpty() method.
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function onChange($property_name) {
+    $this->entity->onChange($property_name);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDataDefinition() {
+    return $this->entity->getDataDefinition();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getValue() {
+    // TODO: Implement getValue() method.
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setValue($value, $notify = TRUE) {
+    // TODO: Implement setValue() method.
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getString() {
+    // TODO: Implement getString() method.
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getConstraints() {
+    return array();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validate() {
+    return $this->entity->validate();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function applyDefaultValue($notify = TRUE) {
+    // TODO: Implement applyDefaultValue() method.
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getName() {
+    // TODO: Implement getName() method.
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getParent() {
+    // TODO: Implement getParent() method.
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getRoot() {
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getPropertyPath() {
+    // TODO: Implement getPropertyPath() method.
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setContext($name = NULL, TypedDataInterface $parent = NULL) {
+    // TODO: Implement setContext() method.
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIterator() {
+    return $this->entity->getIterator();
+  }
+
+}
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 ee27996..718b203 100644
--- a/core/lib/Drupal/Core/Field/FieldItemInterface.php
+++ b/core/lib/Drupal/Core/Field/FieldItemInterface.php
@@ -89,7 +89,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 4305ccd..f725851 100644
--- a/core/lib/Drupal/Core/Field/FieldItemList.php
+++ b/core/lib/Drupal/Core/Field/FieldItemList.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Entity\ContentEntityInterface;
+use Drupal\Core\Entity\Plugin\DataType\EntityTypedDataWrapper;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\TypedData\DataDefinitionInterface;
 use Drupal\Core\TypedData\Plugin\DataType\ItemList;
@@ -55,7 +56,7 @@ public function __construct(DataDefinitionInterface $definition, $name = NULL, T
    * {@inheritdoc}
    */
   public function getEntity() {
-    return $this->getParent();
+    return $this->getParent() instanceof EntityTypedDataWrapper ? $this->getParent()->getEntity() : $this->getParent();
   }
 
   /**
diff --git a/core/lib/Drupal/Core/TypedData/TranslatableInterface.php b/core/lib/Drupal/Core/TypedData/TranslatableInterface.php
index 999bfb7..58dadbd 100644
--- a/core/lib/Drupal/Core/TypedData/TranslatableInterface.php
+++ b/core/lib/Drupal/Core/TypedData/TranslatableInterface.php
@@ -46,7 +46,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);
@@ -54,7 +54,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();
@@ -79,7 +79,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/modules/comment/src/Plugin/Field/FieldWidget/CommentWidget.php b/core/modules/comment/src/Plugin/Field/FieldWidget/CommentWidget.php
index b4a8565..628ec43 100644
--- a/core/modules/comment/src/Plugin/Field/FieldWidget/CommentWidget.php
+++ b/core/modules/comment/src/Plugin/Field/FieldWidget/CommentWidget.php
@@ -29,7 +29,7 @@ class CommentWidget extends WidgetBase {
    */
   public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
     $field = $this->fieldDefinition;
-    $entity = $items->getParent();
+    $entity = $items->getEntity();
 
     // Get default value from the field instance.
     $field_default_values = $this->fieldDefinition->getDefaultValue($entity);
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 968ebfb..6f62377 100644
--- a/core/modules/serialization/tests/src/Normalizer/EntityNormalizerTest.php
+++ b/core/modules/serialization/tests/src/Normalizer/EntityNormalizerTest.php
@@ -73,10 +73,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 b6859dc..355e59b 100644
--- a/core/modules/system/src/Tests/Entity/EntityFieldTest.php
+++ b/core/modules/system/src/Tests/Entity/EntityFieldTest.php
@@ -7,7 +7,9 @@
 
 namespace Drupal\system\Tests\Entity;
 
+use Drupal\Core\Entity\Annotation\EntityType;
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\Plugin\DataType\EntityTypedDataWrapper;
 use Drupal\Core\Field\FieldDefinition;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldItemListInterface;
@@ -405,27 +407,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);
+    $wrapper = new EntityTypedDataWrapper($entity);
+    $this->assertIdentical($wrapper->getRoot(), $wrapper, 'Entity is root object.');
+    $this->assertEqual($wrapper->getPropertyPath(), '');
+    $this->assertEqual($wrapper->getName(), '');
+    $this->assertEqual($wrapper->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.');
@@ -465,9 +468,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)));
   }
 
   /**
@@ -493,7 +496,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(new EntityTypedDataWrapper($entity), 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 a0ec726..5b9cb38 100644
--- a/core/modules/system/src/Tests/Entity/EntityUUIDTest.php
+++ b/core/modules/system/src/Tests/Entity/EntityUUIDTest.php
@@ -79,7 +79,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 dceab23..bba6631 100644
--- a/core/modules/system/src/Tests/Entity/EntityValidationTest.php
+++ b/core/modules/system/src/Tests/Entity/EntityValidationTest.php
@@ -124,7 +124,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.');
 
@@ -142,7 +142,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/tests/Drupal/Tests/Core/Entity/ContentEntityBaseUnitTest.php b/core/tests/Drupal/Tests/Core/Entity/ContentEntityBaseUnitTest.php
index 08fa85c..366fd11 100644
--- a/core/tests/Drupal/Tests/Core/Entity/ContentEntityBaseUnitTest.php
+++ b/core/tests/Drupal/Tests/Core/Entity/ContentEntityBaseUnitTest.php
@@ -8,6 +8,7 @@
 namespace Drupal\Tests\Core\Entity;
 
 use Drupal\Core\DependencyInjection\ContainerBuilder;
+use Drupal\Core\Entity\Plugin\DataType\EntityTypedDataWrapper;
 use Drupal\Core\Field\FieldDefinition;
 use Drupal\Core\Field\FieldItemBase;
 use Drupal\Tests\UnitTestCase;
@@ -280,23 +281,6 @@ public function testPreSaveRevision() {
   }
 
   /**
-   * @covers ::getString
-   */
-  public function testGetString() {
-    $label = $this->randomName();
-    /** @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() {
@@ -310,11 +294,11 @@ public function testValidate() {
     $non_empty_violation_list->add($violation);
     $validator->expects($this->at(0))
       ->method('validate')
-      ->with($this->entity)
+      ->with(new EntityTypedDataWrapper($this->entity))
       ->will($this->returnValue($empty_violation_list));
     $validator->expects($this->at(1))
       ->method('validate')
-      ->with($this->entity)
+      ->with(new EntityTypedDataWrapper($this->entity))
       ->will($this->returnValue($non_empty_violation_list));
     $this->typedDataManager->expects($this->exactly(2))
       ->method('getValidator')
@@ -324,50 +308,6 @@ public function testValidate() {
   }
 
   /**
-   * @covers ::getConstraints
-   */
-  public function testGetConstraints() {
-    $this->assertInternalType('array', $this->entity->getConstraints());
-  }
-
-  /**
-   * @covers ::getName
-   */
-  public function testGetName() {
-    $this->assertNull($this->entity->getName());
-  }
-
-  /**
-   * @covers ::getRoot
-   */
-  public function testGetRoot() {
-    $this->assertSame(spl_object_hash($this->entity), spl_object_hash($this->entity->getRoot()));
-  }
-
-  /**
-   * @covers ::getPropertyPath
-   */
-  public function testGetPropertyPath() {
-    $this->assertSame('', $this->entity->getPropertyPath());
-  }
-
-  /**
-   * @covers ::getParent
-   */
-  public function testGetParent() {
-    $this->assertNull($this->entity->getParent());
-  }
-
-  /**
-   * @covers ::setContext
-   */
-  public function testSetContext() {
-    $name = $this->randomName();
-    $parent = $this->getMock('\Drupal\Core\TypedData\TypedDataInterface');
-    $this->entity->setContext($name, $parent);
-  }
-
-  /**
    * @covers ::bundle
    */
   public function testBundle() {
