 core/modules/file/src/Entity/File.php              | 31 ++++++++++++++++++++++
 .../hal/src/Normalizer/ContentEntityNormalizer.php |  9 +++++--
 .../EntityTestLabelHalJsonAnonTest.php             | 10 -------
 .../EntityResource/Item/ItemHalJsonTestBase.php    | 10 -------
 .../EntityReferenceFieldItemNormalizer.php         |  5 ++--
 .../EntityReferenceFieldItemNormalizerTest.php     | 14 ++++++++--
 .../Drupal/Tests/Listeners/DeprecationListener.php |  1 -
 7 files changed, 53 insertions(+), 27 deletions(-)

diff --git a/core/modules/file/src/Entity/File.php b/core/modules/file/src/Entity/File.php
index a9ade9e..dee25ab 100644
--- a/core/modules/file/src/Entity/File.php
+++ b/core/modules/file/src/Entity/File.php
@@ -7,6 +7,7 @@
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
+use Drupal\Core\Url;
 use Drupal\file\FileInterface;
 use Drupal\user\UserInterface;
 
@@ -71,12 +72,42 @@ public function setFileUri($uri) {
    * @see file_url_transform_relative()
    */
   public function url($rel = 'canonical', $options = []) {
+    // @todo Remove this work-around before Drupal 9.0.0. This was introduced as
+    // a temporary work-around in https://www.drupal.org/node/2277705 to provide
+    // REST support for file entities. https://www.drupal.org/node/2825487 makes
+    // this obsolete.
     return file_create_url($this->getFileUri());
   }
 
   /**
    * {@inheritdoc}
    */
+  public function toUrl($rel = 'canonical', array $options = []) {
+    // Lie because we must provide BC.
+    // @see ::url()
+    // @todo Remove in https://www.drupal.org/node/2825487.
+    if ($rel === 'canonical') {
+      return Url::fromUri($this->url());
+    }
+    return parent::toUrl($rel, $options);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function hasLinkTemplate($rel) {
+    // Lie because we must provide BC.
+    // @see ::url()
+    // @todo Remove in https://www.drupal.org/node/2825487.
+    if ($rel === 'canonical') {
+      return TRUE;
+    }
+    return parent::hasLinkTemplate($rel);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function getMimeType() {
     return $this->get('filemime')->value;
   }
diff --git a/core/modules/hal/src/Normalizer/ContentEntityNormalizer.php b/core/modules/hal/src/Normalizer/ContentEntityNormalizer.php
index 4a9f7c4..0d23358 100644
--- a/core/modules/hal/src/Normalizer/ContentEntityNormalizer.php
+++ b/core/modules/hal/src/Normalizer/ContentEntityNormalizer.php
@@ -179,17 +179,22 @@ public function denormalize($data, $class, $format = NULL, array $context = [])
    *
    * @param \Drupal\Core\Entity\EntityInterface $entity
    *   The entity.
+   * @param array $context
+   *   Normalization/serialization context.
+   *
    * @return string
    *   The entity URI.
    */
-  protected function getEntityUri(EntityInterface $entity) {
+  protected function getEntityUri(EntityInterface $entity, array $context = []) {
     // Some entity types don't provide a canonical link template, at least call
     // out to ->url().
     if ($entity->isNew() || !$entity->hasLinkTemplate('canonical')) {
       return $entity->url('canonical', []);
     }
     $url = $entity->urlInfo('canonical', ['absolute' => TRUE]);
-    return $url->setRouteParameter('_format', 'hal_json')->toString();
+    $generated_url = $url->setRouteParameter('_format', 'hal_json')->toString(TRUE);
+    $this->addCacheableDependency($context, $generated_url);
+    return $generated_url->getGeneratedUrl();
   }
 
   /**
diff --git a/core/modules/hal/tests/src/Functional/EntityResource/EntityTestLabel/EntityTestLabelHalJsonAnonTest.php b/core/modules/hal/tests/src/Functional/EntityResource/EntityTestLabel/EntityTestLabelHalJsonAnonTest.php
index f95ea5c..bcad047 100644
--- a/core/modules/hal/tests/src/Functional/EntityResource/EntityTestLabel/EntityTestLabelHalJsonAnonTest.php
+++ b/core/modules/hal/tests/src/Functional/EntityResource/EntityTestLabel/EntityTestLabelHalJsonAnonTest.php
@@ -90,14 +90,4 @@ protected function getNormalizedPostEntity() {
     ];
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  protected function getExpectedCacheContexts() {
-    return [
-      'url.site',
-      'user.permissions',
-    ];
-  }
-
 }
diff --git a/core/modules/hal/tests/src/Functional/EntityResource/Item/ItemHalJsonTestBase.php b/core/modules/hal/tests/src/Functional/EntityResource/Item/ItemHalJsonTestBase.php
index 24157e5..dfb2e4d 100644
--- a/core/modules/hal/tests/src/Functional/EntityResource/Item/ItemHalJsonTestBase.php
+++ b/core/modules/hal/tests/src/Functional/EntityResource/Item/ItemHalJsonTestBase.php
@@ -87,14 +87,4 @@ protected function getNormalizedPostEntity() {
     ];
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  protected function getExpectedCacheContexts() {
-    return [
-      'url.site',
-      'user.permissions',
-    ];
-  }
-
 }
diff --git a/core/modules/serialization/src/Normalizer/EntityReferenceFieldItemNormalizer.php b/core/modules/serialization/src/Normalizer/EntityReferenceFieldItemNormalizer.php
index ea2e020..c0a83b7 100644
--- a/core/modules/serialization/src/Normalizer/EntityReferenceFieldItemNormalizer.php
+++ b/core/modules/serialization/src/Normalizer/EntityReferenceFieldItemNormalizer.php
@@ -51,8 +51,9 @@ public function normalize($field_item, $format = NULL, array $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.
-      if ($url = $entity->url('canonical')) {
-        $values['url'] = $url;
+      if ($entity->hasLinkTemplate('canonical') && $url = $entity->toUrl('canonical')->toString(TRUE)) {
+        $this->addCacheableDependency($context, $url);
+        $values['url'] = $url->getGeneratedUrl();
       }
     }
     return $values;
diff --git a/core/modules/serialization/tests/src/Unit/Normalizer/EntityReferenceFieldItemNormalizerTest.php b/core/modules/serialization/tests/src/Unit/Normalizer/EntityReferenceFieldItemNormalizerTest.php
index e9df564..f0849d7 100644
--- a/core/modules/serialization/tests/src/Unit/Normalizer/EntityReferenceFieldItemNormalizerTest.php
+++ b/core/modules/serialization/tests/src/Unit/Normalizer/EntityReferenceFieldItemNormalizerTest.php
@@ -4,12 +4,14 @@
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\Core\GeneratedUrl;
 use Drupal\Core\TypedData\TypedDataInterface;
 use Drupal\Core\Entity\EntityRepositoryInterface;
 use Drupal\Core\Entity\FieldableEntityInterface;
 use Drupal\Core\Field\FieldItemInterface;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
+use Drupal\Core\Url;
 use Drupal\serialization\Normalizer\EntityReferenceFieldItemNormalizer;
 use Drupal\Tests\UnitTestCase;
 use Prophecy\Argument;
@@ -104,9 +106,17 @@ public function testSupportsDenormalization() {
   public function testNormalize() {
     $test_url = '/test/100';
 
+    $generated_url = (new GeneratedUrl())->setGeneratedUrl($test_url);
+
+    $url = $this->prophesize(Url::class);
+    $url->toString(TRUE)
+      ->willReturn($generated_url);
+
     $entity = $this->prophesize(EntityInterface::class);
-    $entity->url('canonical')
-      ->willReturn($test_url)
+    $entity->hasLinkTemplate('canonical')
+      ->willReturn(TRUE);
+    $entity->toUrl('canonical')
+      ->willReturn($url)
       ->shouldBeCalled();
     $entity->uuid()
       ->willReturn('080e3add-f9d5-41ac-9821-eea55b7b42fb')
diff --git a/core/tests/Drupal/Tests/Listeners/DeprecationListener.php b/core/tests/Drupal/Tests/Listeners/DeprecationListener.php
index 3673376..7222fdf 100644
--- a/core/tests/Drupal/Tests/Listeners/DeprecationListener.php
+++ b/core/tests/Drupal/Tests/Listeners/DeprecationListener.php
@@ -109,7 +109,6 @@ public static function getSkippedDeprecations() {
       'CommentVariablePerCommentType is deprecated in Drupal 8.4.x and will be removed before Drupal 9.0.x. Use \Drupal\node\Plugin\migrate\source\d6\NodeType instead.',
       'The Drupal\config_translation\Plugin\migrate\source\d6\I18nProfileField is deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0. Instead, use Drupal\config_translation\Plugin\migrate\source\d6\ProfileFieldTranslation',
       'The Drupal\migrate_drupal\Plugin\migrate\source\d6\i18nVariable is deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0. Instead, use Drupal\migrate_drupal\Plugin\migrate\source\d6\VariableTranslation',
-      'Implicit cacheability metadata bubbling (onto the global render context) in normalizers is deprecated since Drupal 8.5.0 and will be removed in Drupal 9.0.0. Use the "cacheability" serialization context instead, for explicit cacheability metadata bubbling. See https://www.drupal.org/node/2918937',
       'Automatically creating the first item for computed fields is deprecated in Drupal 8.5.x and will be removed before Drupal 9.0.0. Use \Drupal\Core\TypedData\ComputedItemListTrait instead.',
     ];
   }
