diff --git a/core/modules/jsonld/lib/Drupal/jsonld/JsonldBundle.php b/core/modules/jsonld/lib/Drupal/jsonld/JsonldBundle.php
index 3024883..52eb7b6 100644
--- a/core/modules/jsonld/lib/Drupal/jsonld/JsonldBundle.php
+++ b/core/modules/jsonld/lib/Drupal/jsonld/JsonldBundle.php
@@ -27,33 +27,23 @@ public function build(ContainerBuilder $container) {
     // Normalizer::supportsNormalization(). Since the first matching Normalizer
     // is used, Normalizers should be ordered from most specific to least
     // specific.
-    $normalizers = array(
-      // Field Item.
-      'entity_reference' => array(
-        'jsonld' => 'Drupal\jsonld\JsonldEntityReferenceNormalizer',
-      ),
-      'field_item' => array(
-        'jsonld' => 'Drupal\jsonld\JsonldFieldItemNormalizer',
-      ),
-      // Entity.
-      'entity' => array(
-        'jsonld' => 'Drupal\jsonld\JsonldEntityNormalizer',
-      ),
-      // RDF Schema.
-      'rdf_schema' => array(
-        'jsonld' => 'Drupal\jsonld\JsonldRdfSchemaNormalizer',
-      ),
-    );
-
-    // Add Normalizers to service container.
-    foreach ($normalizers as $supported_class => $formats) {
-      foreach ($formats as $format => $normalizer_class) {
-        $container->register("serializer.normalizer.{$supported_class}.{$format}", $normalizer_class)
-          ->addArgument(new Reference('rdf.site_schema_manager'))
-          ->addArgument(new Reference('rdf.mapping_manager'))
-          ->addTag('normalizer', array('priority' => $priority));
-      }
-    }
+    $container->register('serializer.normalizer.entity_reference.jsonld', 'Drupal\jsonld\JsonldEntityReferenceNormalizer')
+      ->addArgument(new Reference('rdf.site_schema_manager'))
+      ->addArgument(new Reference('rdf.mapping_manager'))
+      ->addMethodCall('setEntityResolver', array(new Reference('serializer.entity_resolver')))
+      ->addTag('normalizer', array('priority' => $priority));
+    $container->register('serializer.normalizer.field_item.jsonld', 'Drupal\jsonld\JsonldFieldItemNormalizer')
+      ->addArgument(new Reference('rdf.site_schema_manager'))
+      ->addArgument(new Reference('rdf.mapping_manager'))
+      ->addTag('normalizer', array('priority' => $priority));
+    $container->register('serializer.normalizer.entity.jsonld', 'Drupal\jsonld\JsonldEntityNormalizer')
+      ->addArgument(new Reference('rdf.site_schema_manager'))
+      ->addArgument(new Reference('rdf.mapping_manager'))
+      ->addTag('normalizer', array('priority' => $priority));
+    $container->register('serializer.normalizer.rdf_schema.jsonld', 'Drupal\jsonld\JsonldRdfSchemaNormalizer')
+      ->addArgument(new Reference('rdf.site_schema_manager'))
+      ->addArgument(new Reference('rdf.mapping_manager'))
+      ->addTag('normalizer', array('priority' => $priority));
 
     // Add the encoder to the service container. Encoders can only specify which
     // format they support in Encoder::supportsEncoding().
diff --git a/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityNormalizer.php b/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityNormalizer.php
index ab662b3..74ede13 100644
--- a/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityNormalizer.php
+++ b/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityNormalizer.php
@@ -112,9 +112,13 @@ public function denormalize($data, $class, $format = null, array $context = arra
       // The vnd.drupal.ld+json mime type will always use language keys, per
       // http://drupal.org/node/1838700.
       foreach ($incomingFieldValues as $langcode => $incomingFieldItems) {
-        $fieldValue = $this->serializer->denormalize($incomingFieldItems, $fieldItemClass, $format);
+        $field_value = array();
+        $context['field_definition'] = $entity->getPropertyDefinition($fieldName);
+        foreach ($incomingFieldItems as $field_item) {
+          $field_value[] = $this->serializer->denormalize($field_item, $fieldItemClass, $format, $context);
+        }
         $entity->getTranslation($langcode)
-          ->set($fieldName, $fieldValue);
+          ->set($fieldName, $field_value);
       }
     }
     return $entity;
diff --git a/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityReferenceNormalizer.php b/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityReferenceNormalizer.php
index f57066d..5e53115 100644
--- a/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityReferenceNormalizer.php
+++ b/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityReferenceNormalizer.php
@@ -7,10 +7,8 @@
 
 namespace Drupal\jsonld;
 
-use Drupal\Core\Cache\DatabaseBackend;
-use Drupal\Core\Entity\EntityNG;
 use Drupal\jsonld\JsonldNormalizerBase;
-use Drupal\rdf\SiteSchema\SiteSchemaManager;
+use Drupal\serialization\EntityResolver\UuidReferenceInterface;
 use ReflectionClass;
 use Symfony\Component\Serializer\Exception\RuntimeException;
 use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
@@ -18,7 +16,7 @@
 /**
  * Converts an EntityReferenceItem to a JSON-LD array structure.
  */
-class JsonldEntityReferenceNormalizer extends JsonldNormalizerBase implements DenormalizerInterface {
+class JsonldEntityReferenceNormalizer extends JsonldNormalizerBase implements DenormalizerInterface, UuidReferenceInterface {
 
   /**
    * The interface or class that this Normalizer supports.
@@ -31,23 +29,31 @@ class JsonldEntityReferenceNormalizer extends JsonldNormalizerBase implements De
    * Implements \Symfony\Component\Serializer\Normalizer\NormalizerInterface::normalize()
    */
   public function normalize($object, $format = NULL, array $context = array()) {
-    // @todo If an $options parameter is added to the serialize signature, as
+    $return = array();
+    // @todo Since the context parameter was added to Serilizer's interface, as
     // requested in https://github.com/symfony/symfony/pull/4938, then instead
     // of creating the array of properties, we could simply call normalize and
     // pass in the referenced entity with a flag that ensures it is rendered as
     // a node reference and not a node definition.
     $entity_wrapper = new JsonldEntityWrapper($object->entity, $format, $this->serializer, $this->siteSchemaManager);
-    return array(
-      '@id' => $entity_wrapper->getId(),
-    );
-  }
+
+    $return['@id'] = $entity_wrapper->getId();
+
+    // @todo Remove this if statement once all entities are EntityNG.
+    if ($object instanceof \Drupal\Core\Entity\EntityNG) {
+      $properties = $entity_wrapper->getProperties();
+      $return['uuid'] = $properties['uuid'];
+    }
+
+    return $return;
+   }
 
   /**
    * Implements \Symfony\Component\Serializer\Normalizer\DenormalizerInterface::denormalize()
    */
   public function denormalize($data, $class, $format = null, array $context = array()) {
-    // @todo Support denormalization for Entity Reference.
-    return array();
+    $target_type = $context['field_definition']['settings']['target_type'];
+    return $this->entityResolver->resolve($this, $data, $target_type);
   }
 
   /**
@@ -58,4 +64,21 @@ public function supportsDenormalization($data, $type, $format = NULL) {
     return in_array($format, static::$format) && ($reflection->getName() == static::$supportedInterfaceOrClass || $reflection->isSubclassOf(static::$supportedInterfaceOrClass));
   }
 
+  /**
+   * Implements \Drupal\serialization\EntityResolver\UuidReferenceInterface::getUuid().
+   */
+  public function getUuid($data) {
+    if (isset($data['uuid'])) {
+      $uuid = $data['uuid'];
+      while (is_array($uuid)) {
+        $uuid = reset($uuid);
+      }
+      return $uuid;
+    }
+  }
+
+  public function setEntityResolver($entity_resolver) {
+    $this->entityResolver = $entity_resolver;
+  }
+
 }
diff --git a/core/modules/jsonld/lib/Drupal/jsonld/Tests/DenormalizeTest.php b/core/modules/jsonld/lib/Drupal/jsonld/Tests/DenormalizeTest.php
new file mode 100644
index 0000000..b55fe04
--- /dev/null
+++ b/core/modules/jsonld/lib/Drupal/jsonld/Tests/DenormalizeTest.php
@@ -0,0 +1,188 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\jsonld\Tests\DenormalizeTest.
+ */
+
+namespace Drupal\jsonld\Tests;
+
+use Drupal\rdf\SiteSchema\SiteSchema;
+use Symfony\Component\Serializer\Exception\UnexpectedValueException;
+
+class DenormalizeTest extends NormalizerTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('entity_reference');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Denormalize Test',
+      'description' => 'Test that entities can be denormalized from JSON-LD.',
+      'group' => 'JSON-LD',
+    );
+  }
+
+  public function setUp() {
+    parent::setUp();
+    $schema = new SiteSchema(SiteSchema::CONTENT_DEPLOYMENT);
+    $this->bundle_uri = $schema->bundle('entity_test', 'entity_test')->getUri();
+  }
+
+  /**
+   * Test that fields with literal values can be denormalized.
+   */
+  function testBasicDenormalize() {
+    $incoming_data = array(
+      '@type' => $this->bundle_uri,
+      'name' => array(
+        'en' => array(
+          array(
+            'value' => $this->randomName(),
+          ),
+        ),
+        'de' => array(
+          array(
+            'value' => $this->randomName(),
+          ),
+        ),
+      ),
+      'field_test_text' => array(
+        'und' => array(
+          array(
+            'value' => $this->randomName(),
+            'format' => 'full_html',
+          ),
+        ),
+      ),
+    );
+
+    // Test valid request.
+    $serializer = $this->container->get('serializer');
+    $entity = $serializer->denormalize($incoming_data, 'Drupal\Core\Entity\EntityNG', $this->format);
+    $this->assertEqual('entity_test', $entity->bundle(), "Denormalize creates entity with correct bundle.");
+    $this->assertEqual($incoming_data['name']['en'], $entity->get('name')->getValue(), "Translatable field denormalized correctly in default language.");
+    $this->assertEqual($incoming_data['name']['de'], $entity->getTranslation('de')->get('name')->getValue(), "Translatable field denormalized correctly in translation language.");
+    $this->assertEqual($incoming_data['field_test_text']['und'], $entity->get('field_test_text')->getValue(), "Untranslatable field denormalized correctly.");
+
+    // Test request without @type.
+    unset($incoming_data['@type']);
+    try {
+      $serializer->denormalize($incoming_data, 'Drupal\Core\Entity\EntityNG', $this->format);
+      $this->fail('Trying to denormalize entity data without @type results in exception.');
+    }
+    catch (UnexpectedValueException $e) {
+      $this->pass('Trying to denormalize entity data without @type results in exception.');
+    }
+
+    // Test request with @type that has no valid mapping.
+    $incoming_data['@type'] = 'http://failing-uri.com/type';
+    try {
+      $serializer->denormalize($incoming_data, 'Drupal\Core\Entity\EntityNG', $this->format);
+      $this->fail('Trying to denormalize entity data with unrecognized @type results in exception.');
+    }
+    catch (UnexpectedValueException $e) {
+      $this->pass('Trying to denormalize entity data with unrecognized @type results in exception.');
+    }
+  }
+
+  /**
+   * Test that fields with resource values can be denormalized.
+   */
+  function testEntityReferenceDenormalize() {
+    $incoming_data = array(
+      '@type' => $this->bundle_uri,
+      'name' => array(
+        'en' => array(
+          array(
+            'value' => $this->randomName(),
+          ),
+        ),
+      ),
+      'user_id' => array(
+        'und' => array(
+          array(
+            '@id' => 'http://example.org/user/foo',
+          ),
+        ),
+      ),
+    );
+
+    // Deserialize the data.
+    $serializer = $this->container->get('serializer');
+    $entity = $serializer->denormalize($incoming_data, 'Drupal\Core\Entity\EntityNG', $this->format);
+
+    // Test the null value handler.
+    $this->assertEqual(array(NULL), $entity->get('user_id')->getValue(), 'The null value entity reference handler works.');
+  }
+
+  /**
+   * Test that fields with resource values can be denormalized.
+   *
+   * @todo Move this to serialization tests once we have a JSON deserializer.
+   */
+  function testUuidEntityReferenceHandler() {
+    // Create the test field.
+    $field = array(
+      'settings' => array(
+        'target_type' => 'entity_test',
+      ),
+      'field_name' => 'field_test_entity_reference',
+      'type' => 'entity_reference',
+    );
+    field_create_field($field);
+
+    // Create the test field instance.
+    $instance = array(
+      'entity_type' => 'entity_test',
+      'field_name' => 'field_test_entity_reference',
+      'bundle' => 'entity_test',
+    );
+    field_create_instance($instance);
+
+    // Create an entity to get the UUID from.
+    $entity = entity_create('entity_test', array('type' => 'entity_test'));
+    $entity->set('name', 'foobar');
+    $entity->set('field_test_entity_reference', NULL);
+    $entity->save();
+
+    $incoming_data = array(
+      '@type' => $this->bundle_uri,
+      'name' => array(
+        'en' => array(
+          array(
+            'value' => $this->randomName(),
+          ),
+        ),
+      ),
+      'field_test_entity_reference' => array(
+        'und' => array(
+          array(
+            '@id' => 'http://example.org/bar',
+            'uuid' => array(
+              'und' => array(
+                array(
+                  'value' => $entity->uuid(),
+                ),
+              ),
+            ),
+          ),
+        ),
+      ),
+    );
+
+    // Deserialize the data.
+    $serializer = $this->container->get('serializer');
+    $deserialized_entity = $serializer->denormalize($incoming_data, 'Drupal\Core\Entity\EntityNG', $this->format);
+
+    // Test that the correct value was set for the entity reference field.
+    $deserialized_field_value = $deserialized_entity->get('field_test_entity_reference')->getValue();
+    $expected_field_value = array(array('target_id' => $entity->id()));
+    $this->assertEqual($deserialized_field_value, $expected_field_value, 'Entity reference field is properly set based on UUID.');
+
+  }
+}
diff --git a/core/modules/jsonld/lib/Drupal/jsonld/Tests/JsonldTestSetupHelper.php b/core/modules/jsonld/lib/Drupal/jsonld/Tests/JsonldTestSetupHelper.php
index d0eb0c3..ddc4b98 100644
--- a/core/modules/jsonld/lib/Drupal/jsonld/Tests/JsonldTestSetupHelper.php
+++ b/core/modules/jsonld/lib/Drupal/jsonld/Tests/JsonldTestSetupHelper.php
@@ -8,6 +8,7 @@
 namespace Drupal\jsonld\Tests;
 
 use Drupal\Core\Cache\DatabaseBackend;
+use Drupal\Core\Language\Language;
 use Drupal\jsonld\JsonldEncoder;
 use Drupal\jsonld\JsonldEntityNormalizer;
 use Drupal\jsonld\JsonldEntityReferenceNormalizer;
@@ -20,6 +21,8 @@
 
 /**
  * Constructs services for JSON-LD tests.
+ *
+ * @todo Remove this once REST tests use DrupalUnitTestBase.
  */
 class JsonldTestSetupHelper {
 
@@ -93,4 +96,16 @@ public function getSiteSchemaManager() {
   public function getRdfMappingManager() {
     return $this->rdfMappingManager;
   }
+
+  /**
+   * Create a second language to use when testing multilingual values.
+   */
+  public function saveSecondLanguage() {
+    // Add German as a language.
+    $language = new Language(array(
+      'langcode' => 'de',
+      'name' => 'Deutsch',
+    ));
+    language_save($language);
+  }
 }
diff --git a/core/modules/jsonld/lib/Drupal/jsonld/Tests/NormalizeDenormalizeTest.php b/core/modules/jsonld/lib/Drupal/jsonld/Tests/NormalizeDenormalizeTest.php
deleted file mode 100644
index a9e057d..0000000
--- a/core/modules/jsonld/lib/Drupal/jsonld/Tests/NormalizeDenormalizeTest.php
+++ /dev/null
@@ -1,213 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains Drupal\jsonld\Tests\NormalizeDenormalizeTest.
- */
-
-namespace Drupal\jsonld\Tests;
-
-use Drupal\Core\Language\Language;
-use Drupal\rdf\SiteSchema\SiteSchema;
-use Drupal\simpletest\WebTestBase;
-use Drupal\Core\DependencyInjection\ContainerBuilder;
-use Symfony\Component\Serializer\Exception\UnexpectedValueException;
-
-/**
- * Test the vendor specific JSON-LD normalizer.
- *
- * This is implemented as a WebTest because it requires use of the Entity API.
- */
-class NormalizeDenormalizeTest extends WebTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = array('entity_test', 'jsonld', 'language', 'rdf');
-
-  /**
-   * The format being tested.
-   */
-  protected static $format = 'drupal_jsonld';
-
-  /**
-   * The Normalizers to be tested.
-   */
-  protected $normalizers;
-
-  public static function getInfo() {
-    return array(
-      'name' => 'Normalize/Denormalize Test',
-      'description' => "Test that entities can be normalized/denormalized in JSON-LD.",
-      'group' => 'JSON-LD',
-    );
-  }
-
-  /**
-   * Add the normalizer to be tested.
-   */
-  function setUp() {
-    parent::setUp();
-
-    $setup_helper = new JsonldTestSetupHelper();
-    $this->normalizers = $setup_helper->getNormalizers();
-
-    // Add German as a language.
-    $language = new Language(array(
-      'langcode' => 'de',
-      'name' => 'Deutsch',
-    ));
-    language_save($language);
-  }
-
-  /**
-   * Tests the normalize function.
-   */
-  public function testNormalize() {
-    // Create a German entity.
-    $values = array(
-      'langcode' => 'de',
-      'name' => $this->randomName(),
-      'user_id' => $GLOBALS['user']->uid,
-      'field_test_text' => array(
-        'value' => $this->randomName(),
-        'format' => 'full_html',
-      ),
-    );
-    // Array of translated values.
-    $translationValues = array(
-      'name' => $this->randomName(),
-    );
-
-    $entity = entity_create('entity_test', $values);
-    $entity->save();
-    // Add an English value for name property.
-    $entity->getTranslation('en')->set('name', array(0 => array('value' => $translationValues['name'])));
-
-    $expectedArray = array(
-      '@id' => $this->getEntityId($entity),
-      'uuid' => array(
-        'und' => array(
-          array(
-            'value' => $entity->uuid(),
-          ),
-        ),
-      ),
-      'user_id' => array(
-        'de' => array(
-          array(
-            '@id' => url('user/' . $values['user_id'], array('absolute' => TRUE)),
-          ),
-        ),
-      ),
-      'name' => array(
-        'de' => array(
-          array(
-            'value' => $values['name'],
-          ),
-        ),
-        'en' => array(
-          array(
-            'value' => $translationValues['name'],
-          ),
-        ),
-      ),
-      'field_test_text' => array(
-        'und' => array(
-          array(
-            'value' => $values['field_test_text']['value'],
-            'format' => $values['field_test_text']['format'],
-          ),
-        ),
-      ),
-    );
-
-    $normalized = $this->normalizers['entity']->normalize($entity, static::$format);
-    // Test ordering. The @context and @id properties should always be first.
-    $keys = array_keys($normalized);
-    $this->assertEqual($keys[0], '@id', '@id and @context attributes placed correctly.');
-    // Test @id value.
-    $this->assertEqual($normalized['@id'], $expectedArray['@id'], '@id uses correct value.');
-    // Test non-translatable field.
-    $this->assertEqual($normalized['uuid'], $expectedArray['uuid'], 'Non-translatable fields are nested correctly.');
-    // Test single-language translatable.
-    $this->assertEqual($normalized['user_id'], $expectedArray['user_id'], 'Translatable field with single language value is nested correctly.');
-    // Test multi-language translatable.
-    $this->assertEqual($normalized['name'], $expectedArray['name'], 'Translatable field with multiple language values is nested correctly.');
-    // Test multi-property untranslatable field.
-    $this->assertEqual($normalized['field_test_text'], $expectedArray['field_test_text'], 'Field with properties is nested correctly.');
-  }
-
-  function testDenormalize() {
-    $schema = new SiteSchema(SiteSchema::CONTENT_DEPLOYMENT);
-    $bundle_uri = $schema->bundle('entity_test', 'entity_test')->getUri();
-    $incoming_data = array(
-      '@type' => $bundle_uri,
-      'name' => array(
-        'en' => array(
-          array(
-            'value' => $this->randomName(),
-          ),
-        ),
-        'de' => array(
-          array(
-            'value' => $this->randomName(),
-          ),
-        ),
-      ),
-      'field_test_text' => array(
-        'und' => array(
-          array(
-            'value' => $this->randomName(),
-            'format' => 'full_html',
-          ),
-        ),
-      ),
-    );
-
-    // Test valid request.
-    $entity = $this->normalizers['entity']->denormalize($incoming_data, 'Drupal\Core\Entity\EntityNG', static::$format);
-    $this->assertEqual('entity_test', $entity->bundle(), "Denormalize creates entity with correct bundle.");
-    $this->assertEqual($incoming_data['name']['en'], $entity->get('name')->getValue(), "Translatable field denormalized correctly in default language.");
-    $this->assertEqual($incoming_data['name']['de'], $entity->getTranslation('de')->get('name')->getValue(), "Translatable field denormalized correctly in translation language.");
-    $this->assertEqual($incoming_data['field_test_text']['und'], $entity->get('field_test_text')->getValue(), "Untranslatable field denormalized correctly.");
-
-    // Test request without @type.
-    unset($incoming_data['@type']);
-    try {
-      $this->normalizers['entity']->denormalize($incoming_data, 'Drupal\Core\Entity\EntityNG', static::$format);
-      $this->fail('Trying to denormalize entity data without @type results in exception.');
-    }
-    catch (UnexpectedValueException $e) {
-      $this->pass('Trying to denormalize entity data without @type results in exception.');
-    }
-
-    // Test request with @type that has no valid mapping.
-    $incoming_data['@type'] = 'http://failing-uri.com/type';
-    try {
-      $this->normalizers['entity']->denormalize($incoming_data, 'Drupal\Core\Entity\EntityNG', static::$format);
-      $this->fail('Trying to denormalize entity data with unrecognized @type results in exception.');
-    }
-    catch (UnexpectedValueException $e) {
-      $this->pass('Trying to denormalize entity data with unrecognized @type results in exception.');
-    }
-  }
-
-  /**
-   * Get the Entity ID.
-   *
-   * @param \Drupal\Core\Entity\EntityNG $entity
-   *   Entity to get URI for.
-   *
-   * @return string
-   *   Return the entity URI.
-   */
-  protected function getEntityId($entity) {
-    global $base_url;
-    $uriInfo = $entity->uri();
-    return $base_url . '/' . $uriInfo['path'];
-  }
-
-}
diff --git a/core/modules/jsonld/lib/Drupal/jsonld/Tests/NormalizeTest.php b/core/modules/jsonld/lib/Drupal/jsonld/Tests/NormalizeTest.php
new file mode 100644
index 0000000..f8f8f59
--- /dev/null
+++ b/core/modules/jsonld/lib/Drupal/jsonld/Tests/NormalizeTest.php
@@ -0,0 +1,116 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\jsonld\Tests\NormalizeTest.
+ */
+
+namespace Drupal\jsonld\Tests;
+
+/**
+ * Test the vendor specific JSON-LD normalizer.
+ */
+class NormalizeTest extends NormalizerTestBase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Normalize Test',
+      'description' => 'Test that entities can be normalized in JSON-LD.',
+      'group' => 'JSON-LD',
+    );
+  }
+
+  /**
+   * Tests the normalize function.
+   */
+  public function testNormalize() {
+    // Create a German entity.
+    $values = array(
+      'langcode' => 'de',
+      'name' => $this->randomName(),
+      'user_id' => 1,
+      'field_test_text' => array(
+        'value' => $this->randomName(),
+        'format' => 'full_html',
+      ),
+    );
+    // Array of translated values.
+    $translationValues = array(
+      'name' => $this->randomName(),
+    );
+
+    $entity = entity_create('entity_test', $values);
+    $entity->save();
+    // Add an English value for name property.
+    $entity->getTranslation('en')->set('name', array(0 => array('value' => $translationValues['name'])));
+
+    $expectedArray = array(
+      '@id' => $this->getEntityId($entity),
+      'uuid' => array(
+        'und' => array(
+          array(
+            'value' => $entity->uuid(),
+          ),
+        ),
+      ),
+      'user_id' => array(
+        'de' => array(
+          array(
+            '@id' => url('user/' . $values['user_id'], array('absolute' => TRUE)),
+          ),
+        ),
+      ),
+      'name' => array(
+        'de' => array(
+          array(
+            'value' => $values['name'],
+          ),
+        ),
+        'en' => array(
+          array(
+            'value' => $translationValues['name'],
+          ),
+        ),
+      ),
+      'field_test_text' => array(
+        'und' => array(
+          array(
+            'value' => $values['field_test_text']['value'],
+            'format' => $values['field_test_text']['format'],
+          ),
+        ),
+      ),
+    );
+
+    $normalized = $this->container->get('serializer')->normalize($entity, $this->format);
+    // Test ordering. The @context and @id properties should always be first.
+    $keys = array_keys($normalized);
+    $this->assertEqual($keys[0], '@id', '@id and @context attributes placed correctly.');
+    // Test @id value.
+    $this->assertEqual($normalized['@id'], $expectedArray['@id'], '@id uses correct value.');
+    // Test non-translatable field.
+    $this->assertEqual($normalized['uuid'], $expectedArray['uuid'], 'Non-translatable fields are nested correctly.');
+    // Test single-language translatable.
+    $this->assertEqual($normalized['user_id'], $expectedArray['user_id'], 'Translatable field with single language value is nested correctly.');
+    // Test multi-language translatable.
+    $this->assertEqual($normalized['name'], $expectedArray['name'], 'Translatable field with multiple language values is nested correctly.');
+    // Test multi-property untranslatable field.
+    $this->assertEqual($normalized['field_test_text'], $expectedArray['field_test_text'], 'Field with properties is nested correctly.');
+  }
+
+  /**
+   * Get the Entity ID.
+   *
+   * @param \Drupal\Core\Entity\EntityNG $entity
+   *   Entity to get URI for.
+   *
+   * @return string
+   *   Return the entity URI.
+   */
+  protected function getEntityId($entity) {
+    global $base_url;
+    $uriInfo = $entity->uri();
+    return $base_url . '/' . $uriInfo['path'];
+  }
+
+}
diff --git a/core/modules/jsonld/lib/Drupal/jsonld/Tests/NormalizerTestBase.php b/core/modules/jsonld/lib/Drupal/jsonld/Tests/NormalizerTestBase.php
new file mode 100644
index 0000000..4bf0b38
--- /dev/null
+++ b/core/modules/jsonld/lib/Drupal/jsonld/Tests/NormalizerTestBase.php
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\jsonld\Tests\NormalizerTestBase.
+ */
+
+namespace Drupal\jsonld\Tests;
+
+use Drupal\Core\Language\Language;
+use Drupal\rdf\SiteSchema\SiteSchema;
+use Drupal\simpletest\DrupalUnitTestBase;
+use Drupal\Core\DependencyInjection\ContainerBuilder;
+use Symfony\Component\Serializer\Exception\UnexpectedValueException;
+
+/**
+ * Test the vendor specific JSON-LD normalizer.
+ *
+ * This is implemented as a WebTest because it requires use of the Entity API.
+ */
+abstract class NormalizerTestBase extends DrupalUnitTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('field', 'field_sql_storage', 'language', 'system', 'text', 'serialization');
+
+  /**
+   * The format being tested.
+   */
+  protected $format = 'drupal_jsonld';
+
+  /**
+   * Overrides \Drupal\simpletest\DrupalUnitTestBase::setup().
+   */
+  function setUp() {
+    parent::setUp();
+    $this->installSchema('system', 'variable');
+    $this->installSchema('system', 'url_alias');
+    $this->installSchema('field', 'field_config');
+    $this->installSchema('field', 'field_config_instance');
+
+    // English must be added before entity_test is enabled.
+    $this->enableModules(array('language'));
+    $english = new Language(array(
+      'langcode' => 'en',
+      'name' => 'English',
+    ));
+    language_save($english);
+    // Add German as a language.
+    $german = new Language(array(
+      'langcode' => 'de',
+      'name' => 'Deutsch',
+    ));
+    language_save($german);
+
+    $this->enableModules(array('entity_test', 'serialization', 'rdf', 'jsonld', 'user'));
+  }
+
+}
diff --git a/core/modules/jsonld/lib/Drupal/jsonld/Tests/SupportsSerializationTest.php b/core/modules/jsonld/lib/Drupal/jsonld/Tests/SupportsSerializationTest.php
index 38cee8a..5e5698b 100644
--- a/core/modules/jsonld/lib/Drupal/jsonld/Tests/SupportsSerializationTest.php
+++ b/core/modules/jsonld/lib/Drupal/jsonld/Tests/SupportsSerializationTest.php
@@ -8,24 +8,12 @@
 namespace Drupal\jsonld\Tests;
 
 use Drupal\config\Tests\ConfigEntityTest;
-use Drupal\simpletest\WebTestBase;
+use Drupal\jsonld\Tests\NormalizerTestBase;
 
 /**
  * Test the vendor specific JSON-LD normalizer.
  */
-class SupportsSerializationTest extends WebTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = array('entity_test', 'jsonld');
-
-  /**
-   * The format being tested.
-   */
-  protected static $format = 'drupal_jsonld';
+class SupportsSerializationTest extends NormalizerTestBase {
 
   /**
    * The Normalizers to be tested.
@@ -54,28 +42,28 @@ function setUp() {
    * Tests the supportsNormalization function.
    */
   public function testSupportsNormalization() {
-    $format = static::$format;
+    $format = $this->format;
     $supportedEntity = entity_create('entity_test', array());
     $unsupportedEntity = new ConfigEntityTest();
     $field = $supportedEntity->get('uuid');
     $entityreferenceField = $supportedEntity->get('user_id');
 
     // Supported entity.
-    $this->assertTrue($this->normalizers['entity']->supportsNormalization($supportedEntity, static::$format), "Entity normalization is supported for $format on content entities.");
+    $this->assertTrue($this->normalizers['entity']->supportsNormalization($supportedEntity, $format), "Entity normalization is supported for $format on content entities.");
     // Unsupported entity.
-    $this->assertFalse($this->normalizers['entity']->supportsNormalization($unsupportedEntity, static::$format), "Normalization is not supported for other entity types.");
+    $this->assertFalse($this->normalizers['entity']->supportsNormalization($unsupportedEntity, $format), "Normalization is not supported for other entity types.");
 
     // Field item.
-    $this->assertTrue($this->normalizers['field_item']->supportsNormalization($field->offsetGet(0), static::$format), "Field item normalization is supported for $format.");
+    $this->assertTrue($this->normalizers['field_item']->supportsNormalization($field->offsetGet(0), $format), "Field item normalization is supported for $format.");
     // Entity reference field item.
-    $this->assertTrue($this->normalizers['entityreference']->supportsNormalization($entityreferenceField->offsetGet(0), static::$format), "Entity reference field item normalization is supported for $format.");
+    $this->assertTrue($this->normalizers['entityreference']->supportsNormalization($entityreferenceField->offsetGet(0), $format), "Entity reference field item normalization is supported for $format.");
   }
 
   /**
    * Tests the supportsDenormalization function.
    */
   public function testSupportsDenormalization() {
-    $format = static::$format;
+    $format = $this->format;
     $data = array();
     $supportedEntityClass = 'Drupal\Core\Entity\EntityNG';
     $unsupportedEntityClass = 'Drupal\config\Tests\ConfigEntityTest';
@@ -83,14 +71,14 @@ public function testSupportsDenormalization() {
     $entityreferenceFieldClass = 'Drupal\Core\Entity\Field\Type\EntityReferenceItem';
 
     // Supported entity.
-    $this->assertTrue($this->normalizers['entity']->supportsDenormalization($data, $supportedEntityClass, static::$format), "Entity denormalization is supported for $format on content entities.");
+    $this->assertTrue($this->normalizers['entity']->supportsDenormalization($data, $supportedEntityClass, $format), "Entity denormalization is supported for $format on content entities.");
     // Unsupported entity.
-    $this->assertFalse($this->normalizers['entity']->supportsDenormalization($data, $unsupportedEntityClass, static::$format), "Denormalization is not supported for other entity types.");
+    $this->assertFalse($this->normalizers['entity']->supportsDenormalization($data, $unsupportedEntityClass, $format), "Denormalization is not supported for other entity types.");
 
     // Field item.
-    $this->assertTrue($this->normalizers['field_item']->supportsDenormalization($data, $fieldClass, static::$format), "Field item denormalization is supported for $format.");
+    $this->assertTrue($this->normalizers['field_item']->supportsDenormalization($data, $fieldClass, $format), "Field item denormalization is supported for $format.");
     // Entity reference field item.
-    $this->assertTrue($this->normalizers['entityreference']->supportsDenormalization($data, $entityreferenceFieldClass, static::$format), "Entity reference field item denormalization is supported for $format.");
+    $this->assertTrue($this->normalizers['entityreference']->supportsDenormalization($data, $entityreferenceFieldClass, $format), "Entity reference field item denormalization is supported for $format.");
   }
 
 }
diff --git a/core/modules/serialization/lib/Drupal/serialization/EntityResolver/ChainEntityResolver.php b/core/modules/serialization/lib/Drupal/serialization/EntityResolver/ChainEntityResolver.php
new file mode 100644
index 0000000..f8edbb3
--- /dev/null
+++ b/core/modules/serialization/lib/Drupal/serialization/EntityResolver/ChainEntityResolver.php
@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\serialization\EntityResolver\ChainEntityResolver
+ */
+
+namespace Drupal\serialization\EntityResolver;
+
+use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
+
+/**
+ * Resolver delegating the entity resolution to a chain of resolvers.
+ */
+class ChainEntityResolver implements EntityResolverInterface {
+
+  /**
+   * The concrete resolvers.
+   *
+   * @var array
+   */
+  protected $resolvers;
+
+  /**
+   * Constructor.
+   *
+   * @param array $resolvers
+   *   The array of concrete resolvers.
+   */
+  public function __construct(array $resolvers = array()) {
+    $this->resolvers = $resolvers;
+  }
+
+  /**
+   * Implements \Drupal\serialization\EntityResolver\EntityResolverInterface::resolve().
+   */
+  public function resolve(NormalizerInterface $normalizer, $data, $target_type) {
+    foreach ($this->resolvers as $resolver) {
+      if ($resolved = $resolver->resolve($normalizer, $data, $target_type)) {
+        return $resolved;
+      }
+    }
+    return NULL;
+  }
+
+}
diff --git a/core/modules/serialization/lib/Drupal/serialization/EntityResolver/EntityResolverInterface.php b/core/modules/serialization/lib/Drupal/serialization/EntityResolver/EntityResolverInterface.php
new file mode 100644
index 0000000..440a82a
--- /dev/null
+++ b/core/modules/serialization/lib/Drupal/serialization/EntityResolver/EntityResolverInterface.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\serialization\EntityResolver\EntityResolverInterface
+ */
+
+namespace Drupal\serialization\EntityResolver;
+
+use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
+
+interface EntityResolverInterface {
+
+  /**
+   * Resolve an ID to the corresponding entity.
+   *
+   * If the local id is found, the target_id property should be set in the
+   * returned array. Otherwise, if the EntityResolver knows how to dereference
+   * the value, the dereferencer should be set.
+   *
+   * @param \Symfony\Component\Serializer\Normalizer\NormalizerInterface $normalizer
+   *   The normalizer which is handling the data.
+   *
+   * @return array|NULL
+   *   Returns an array containing either target_id or dereferencer, if found.
+   *   Otherwise, return NULL.
+   */
+  public function resolve(NormalizerInterface $normalizer, $data, $target_type);
+
+}
diff --git a/core/modules/serialization/lib/Drupal/serialization/EntityResolver/UuidReferenceInterface.php b/core/modules/serialization/lib/Drupal/serialization/EntityResolver/UuidReferenceInterface.php
new file mode 100644
index 0000000..7bb3a69
--- /dev/null
+++ b/core/modules/serialization/lib/Drupal/serialization/EntityResolver/UuidReferenceInterface.php
@@ -0,0 +1,26 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\serialization\EntityResolver\UuidReferenceInterface
+ */
+
+namespace Drupal\serialization\EntityResolver;
+
+/**
+ * Interface for extracting UUID from entity reference data when denormalizing.
+ */
+interface UuidReferenceInterface {
+
+  /**
+   * Get the uuid from the data array.
+   *
+   * @param array $data
+   *   The data, as was passed into the Normalizer.
+   *
+   * @return string
+   *   A UUID.
+   */
+  public function getUuid($data);
+
+}
\ No newline at end of file
diff --git a/core/modules/serialization/lib/Drupal/serialization/EntityResolver/UuidResolver.php b/core/modules/serialization/lib/Drupal/serialization/EntityResolver/UuidResolver.php
new file mode 100644
index 0000000..2fe4d93
--- /dev/null
+++ b/core/modules/serialization/lib/Drupal/serialization/EntityResolver/UuidResolver.php
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\serialization\EntityResolver\UuidResolver
+ */
+
+namespace Drupal\serialization\EntityResolver;
+
+use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
+
+class UuidResolver implements EntityResolverInterface {
+
+  /**
+   * Implements \Drupal\serialization\EntityResolver\EntityResolverInterface::resolve().
+   */
+  public function resolve(NormalizerInterface $normalizer, $data, $target_type) {
+    if (($normalizer instanceof UuidReferenceInterface) && $uuid = $normalizer->getUuid($data)) {
+      // If an entity with this UUID exists on the site, return the local id.
+      if ($entity = entity_load_by_uuid($target_type, $uuid)) {
+        return array('target_id' => $entity->id());
+      }
+    }
+    return NULL;
+  }
+
+}
diff --git a/core/modules/serialization/lib/Drupal/serialization/RegisterEntityResolversCompilerPass.php b/core/modules/serialization/lib/Drupal/serialization/RegisterEntityResolversCompilerPass.php
new file mode 100644
index 0000000..6399f50
--- /dev/null
+++ b/core/modules/serialization/lib/Drupal/serialization/RegisterEntityResolversCompilerPass.php
@@ -0,0 +1,65 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\serialization\RegisterEntityResolversCompilerPass.
+ */
+
+namespace Drupal\serialization;
+
+use Symfony\Component\DependencyInjection\Reference;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+
+/**
+ * Adds services tagged 'normalizer' and 'encoder' to the Serializer.
+ */
+class RegisterEntityResolversCompilerPass implements CompilerPassInterface {
+
+  /**
+   * Adds services to the Serializer.
+   *
+   * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
+   *   The container to process.
+   */
+  public function process(ContainerBuilder $container) {
+    $definition = $container->getDefinition('serializer.entity_resolver');
+
+    // Retrieve registered Normalizers and Encoders from the container.
+    foreach ($container->findTaggedServiceIds('entity_resolver') as $id => $attributes) {
+      $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0;
+      $resolvers[$priority][] = new Reference($id);
+    }
+
+    // Add the registered concrete EntityResolvers to the ChainEntityResolver.
+    if (!empty($resolvers)) {
+      $definition->replaceArgument(0, $this->sort($resolvers));
+    }
+  }
+
+  /**
+   * Sorts by priority.
+   *
+   * Order services from highest priority number to lowest (reverse sorting).
+   *
+   * @param array $services
+   *   A nested array keyed on priority number. For each priority number, the
+   *   value is an array of Symfony\Component\DependencyInjection\Reference
+   *   objects, each a reference to a normalizer or encoder service.
+   *
+   * @return array
+   *   A flattened array of Reference objects from $services, ordered from high
+   *   to low priority.
+   */
+  protected function sort($services) {
+    $sorted = array();
+    krsort($services);
+
+    // Flatten the array.
+    foreach ($services as $a) {
+      $sorted = array_merge($sorted, $a);
+    }
+
+    return $sorted;
+  }
+}
diff --git a/core/modules/serialization/lib/Drupal/serialization/SerializationBundle.php b/core/modules/serialization/lib/Drupal/serialization/SerializationBundle.php
index a2744b5..7b1b3a1 100644
--- a/core/modules/serialization/lib/Drupal/serialization/SerializationBundle.php
+++ b/core/modules/serialization/lib/Drupal/serialization/SerializationBundle.php
@@ -8,8 +8,10 @@
 namespace Drupal\serialization;
 
 use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Reference;
 use Symfony\Component\HttpKernel\Bundle\Bundle;
 
+
 /**
  * Serialization dependency injection container.
  */
@@ -24,16 +26,28 @@ public function build(ContainerBuilder $container) {
       ->addArgument(array())
       ->addArgument(array());
 
+    // Register the normalizers.
     $container->register('serializer.normalizer.complex_data', 'Drupal\serialization\Normalizer\ComplexDataNormalizer')->addTag('normalizer');
     $container->register('serializer.normalizer.list', 'Drupal\serialization\Normalizer\ListNormalizer')->addTag('normalizer');
     $container->register('serializer.normalizer.typed_data', 'Drupal\serialization\Normalizer\TypedDataNormalizer')->addTag('normalizer');
 
+    // Register the encoders.
     $container->register('serializer.encoder.json', 'Drupal\serialization\Encoder\JsonEncoder')
       ->addTag('encoder', array('format' => array('json' => 'JSON')));
     $container->register('serializer.encoder.xml', 'Drupal\serialization\Encoder\XmlEncoder')
       ->addTag('encoder', array('format' => array('xml' => 'XML')));
 
+    // Add the chain entity resolver with an argument to be replaced in the
+    // compiler pass.
+    $container->register('serializer.entity_resolver', 'Drupal\serialization\EntityResolver\ChainEntityResolver')
+      ->addArgument(array());
+    // Add the concrete entity resolvers.
+    $container->register('serializer.entityresolver.uuid', 'Drupal\serialization\EntityResolver\UuidResolver')
+      ->addTag('entity_resolver');
+
     // Add a compiler pass for adding Normalizers and Encoders to Serializer.
     $container->addCompilerPass(new RegisterSerializationClassesCompilerPass());
+    // Add a compiler pass for adding concrete Resolvers to chain Resolver.
+    $container->addCompilerPass(new RegisterEntityResolversCompilerPass());
   }
 }
