diff --git a/core/modules/serialization/serialization.services.yml b/core/modules/serialization/serialization.services.yml
index 318a90c..070a530 100644
--- a/core/modules/serialization/serialization.services.yml
+++ b/core/modules/serialization/serialization.services.yml
@@ -21,6 +21,10 @@ services:
     class: Drupal\serialization\Normalizer\ComplexDataNormalizer
     tags:
       - { name: normalizer }
+  serializer.normalizer.entity_reference_field_item:
+    class: Drupal\serialization\Normalizer\EntityReferenceFieldItemNormalizer
+    tags:
+      - { name: normalizer, priority: 10 }
   serializer.normalizer.list:
     class: Drupal\serialization\Normalizer\ListNormalizer
     tags:
diff --git a/core/modules/serialization/src/Normalizer/EntityReferenceFieldItemNormalizer.php b/core/modules/serialization/src/Normalizer/EntityReferenceFieldItemNormalizer.php
new file mode 100644
index 0000000..a08ae4a
--- /dev/null
+++ b/core/modules/serialization/src/Normalizer/EntityReferenceFieldItemNormalizer.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\serialization\Normalizer\FileFieldItemNormalizer.
+ */
+
+namespace Drupal\serialization\Normalizer;
+
+/**
+ * Adds the file URI to embedded file entities.
+ */
+class EntityReferenceFieldItemNormalizer extends ComplexDataNormalizer {
+
+  /**
+   * The interface or class that this Normalizer supports.
+   *
+   * @var string
+   */
+  protected $supportedInterfaceOrClass = 'Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem';
+
+  /**
+   * {@inheritdoc}
+   */
+  public function normalize($field_item, $format = NULL, array $context = []) {
+    $values = parent::normalize($field_item, $format, $context);
+
+    // Add a 'url' value if there is a reference and a canonical URL. Hard code
+    // 'canonical' here as config entities override the default $rel parameter
+    // value to 'edit-form.
+    /** @var \Drupal\Core\Entity\EntityInterface $entity */
+    if (($entity = $field_item->get('entity')->getValue()) && ($url = $entity->url('canonical'))) {
+      $values['url'] = $url;
+    }
+
+    return $values;
+  }
+
+}
diff --git a/core/modules/serialization/src/Tests/EntitySerializationTest.php b/core/modules/serialization/src/Tests/EntitySerializationTest.php
index bb305a7..3a9daf8 100644
--- a/core/modules/serialization/src/Tests/EntitySerializationTest.php
+++ b/core/modules/serialization/src/Tests/EntitySerializationTest.php
@@ -40,6 +40,13 @@ class EntitySerializationTest extends NormalizerTestBase {
   protected $entity;
 
   /**
+   * The test user.
+   *
+   * @var \Drupal\user\Entity\User
+   */
+  protected $user;
+
+  /**
    * The serializer service.
    *
    * @var \Symfony\Component\Serializer\Serializer.
@@ -58,10 +65,19 @@ protected function setUp() {
 
     // User create needs sequence table.
     $this->installSchema('system', array('sequences'));
+
+    // Create a test user to use as the entity owner.
+    $this->user = \Drupal::entityManager()->getStorage('user')->create([
+      'name' => 'serialization_test_user',
+      'mail' => 'foo@example.com',
+      'pass' => '123456',
+    ]);
+    $this->user->save();
+
     // Create a test entity to serialize.
     $this->values = array(
       'name' => $this->randomMachineName(),
-      'user_id' => \Drupal::currentUser()->id(),
+      'user_id' => $this->user->id(),
       'field_test_text' => array(
         'value' => $this->randomMachineName(),
         'format' => 'full_html',
@@ -99,7 +115,10 @@ public function testNormalize() {
         array('value' => $this->entity->created->value),
       ),
       'user_id' => array(
-        array('target_id' => $this->values['user_id']),
+        array(
+          'target_id' => $this->user->id(),
+          'url' => $this->user->url(),
+        ),
       ),
       'revision_id' => array(
         array('value' => 1),
@@ -128,22 +147,15 @@ public function testNormalize() {
    * override some default access controls.
    */
   public function testUserNormalize() {
-    $account = User::create([
-      'name' => 'serialization_test_user',
-      'mail' => 'foo@example.com',
-      'pass' => '123456',
-    ]);
-    $account->save();
-
     // Test password isn't available.
-    $normalized = $this->serializer->normalize($account);
+    $normalized = $this->serializer->normalize($this->user);
 
     $this->assertFalse(array_key_exists('pass', $normalized), '"pass" key does not exist in normalized user');
     $this->assertFalse(array_key_exists('mail', $normalized), '"mail" key does not exist in normalized user');
 
     // Test again using our test user, so that our access control override will
     // allow password viewing.
-    $normalized = $this->serializer->normalize($account, NULL, ['account' => $account]);
+    $normalized = $this->serializer->normalize($this->user, NULL, ['account' => $this->user]);
 
     // The key 'pass' will now exist, but the password value should be
     // normalized to NULL.
@@ -179,7 +191,7 @@ public function testSerialize() {
       'name' => '<name><value>' . $this->values['name'] . '</value></name>',
       'type' => '<type><value>entity_test_mulrev</value></type>',
       'created' => '<created><value>' . $this->entity->created->value . '</value></created>',
-      'user_id' => '<user_id><target_id>' . $this->values['user_id'] . '</target_id></user_id>',
+      'user_id' => '<user_id><target_id>' . $this->user->id() . '</target_id><url>' . $this->user->url() . '</url></user_id>',
       'revision_id' => '<revision_id><value>' . $this->entity->getRevisionId() . '</value></revision_id>',
       'default_langcode' => '<default_langcode><value>1</value></default_langcode>',
       'field_test_text' => '<field_test_text><value>' . $this->values['field_test_text']['value'] . '</value><format>' . $this->values['field_test_text']['format'] . '</format></field_test_text>',
diff --git a/core/modules/serialization/tests/src/Unit/Normalizer/EntityReferenceFieldItemNormalizerTest.php b/core/modules/serialization/tests/src/Unit/Normalizer/EntityReferenceFieldItemNormalizerTest.php
new file mode 100644
index 0000000..1adc99c
--- /dev/null
+++ b/core/modules/serialization/tests/src/Unit/Normalizer/EntityReferenceFieldItemNormalizerTest.php
@@ -0,0 +1,125 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\serialization\Unit\Normalizer\EntityReferenceFieldItemNormalizerTest.
+ */
+
+namespace Drupal\Tests\serialization\Unit\Normalizer;
+
+use Drupal\serialization\Normalizer\EntityReferenceFieldItemNormalizer;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * @coversDefaultClass \Drupal\serialization\Normalizer\EntityReferenceFieldItemNormalizer
+ * @group serialization
+ */
+class EntityReferenceFieldItemNormalizerTest extends UnitTestCase {
+
+  /**
+   * The mock serializer.
+   *
+   * @var \Symfony\Component\Serializer\SerializerInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $serializer;
+
+  /**
+   * The normalizer under test.
+   *
+   * @var \Drupal\serialization\Normalizer\EntityReferenceFieldItemNormalizer
+   */
+  protected $normalizer;
+
+  /**
+   * The mock field item.
+   *
+   * @var \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $fieldItem;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    $this->normalizer = new EntityReferenceFieldItemNormalizer();
+
+    $this->serializer = $this->getMockBuilder('Symfony\Component\Serializer\Serializer')
+      ->disableOriginalConstructor()
+      ->setMethods(array('normalize'))
+      ->getMock();
+    // Set up the serializer to return an entity property.
+    $this->serializer->expects($this->any())
+      ->method('normalize')
+      ->willReturn(['value' => 'test']);
+
+    $this->normalizer->setSerializer($this->serializer);
+
+    $this->fieldItem = $this->getMockBuilder('Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $this->fieldItem->expects($this->any())
+      ->method('getIterator')
+      ->willReturn(new \ArrayIterator(['target_id' => []]));
+  }
+
+  /**
+   * @covers ::supportsNormalization
+   */
+  public function testSupportsNormalization() {
+    $this->assertTrue($this->normalizer->supportsNormalization($this->fieldItem));
+    $this->assertFalse($this->normalizer->supportsNormalization(new \stdClass()));
+  }
+
+  /**
+   * @covers ::normalize
+   */
+  public function testNormalize() {
+    $test_url = '/test/100';
+
+    $entity = $this->getMock('Drupal\Core\Entity\EntityInterface');
+    $entity->expects($this->once())
+      ->method('url')
+      ->willReturn($test_url);
+
+    $entity_reference = $this->getMock('Drupal\Core\TypedData\TypedDataInterface');
+    $entity_reference->expects($this->once())
+      ->method('getValue')
+      ->willReturn($entity);
+
+    $this->fieldItem->expects($this->once())
+      ->method('get')
+      ->with('entity')
+      ->willReturn($entity_reference);
+
+    $normalized = $this->normalizer->normalize($this->fieldItem);
+
+    $expected = [
+      'target_id' => ['value' => 'test'],
+      'url' => $test_url,
+    ];
+    $this->assertSame($expected, $normalized);
+  }
+
+  /**
+   * @covers ::normalize
+   */
+  public function testNormalizeWithNoEntity() {
+    $entity_reference = $this->getMock('Drupal\Core\TypedData\TypedDataInterface');
+    $entity_reference->expects($this->once())
+      ->method('getValue')
+      ->willReturn(NULL);
+
+    $this->fieldItem->expects($this->once())
+      ->method('get')
+      ->with('entity')
+      ->willReturn($entity_reference);
+
+    $normalized = $this->normalizer->normalize($this->fieldItem);
+
+    $expected = [
+      'target_id' => ['value' => 'test'],
+    ];
+    $this->assertSame($expected, $normalized);
+  }
+
+}
