diff --git a/core/lib/Drupal/Core/Cache/MutableCacheableDependencyInterface.php b/core/lib/Drupal/Core/Cache/MutableCacheableDependencyInterface.php
new file mode 100644
index 0000000..6434dc1
--- /dev/null
+++ b/core/lib/Drupal/Core/Cache/MutableCacheableDependencyInterface.php
@@ -0,0 +1,52 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\Core\Cache\MutableCacheableDependencyInterface.
+ */
+
+namespace Drupal\Core\Cache;
+
+/**
+ * Allows to add cacheability metadata to an object for the current runtime.
+ *
+ * This must be used when changing an object in a way that affects its
+ * cacheability. For example, when changing the active translation of an entity
+ * based on the current content language then a cache context for that must be
+ * added.
+ */
+interface MutableCacheableDependencyInterface extends CacheableDependencyInterface {
+
+  /**
+   * Adds cache contexts.
+   *
+   * @param string[] $cache_contexts
+   *   The cache contexts to be added.
+   *
+   * @return $this
+   */
+  public function addCacheContexts(array $cache_contexts);
+
+  /**
+   * Adds cache tags.
+   *
+   * @param string[] $cache_tags
+   *   The cache tags to be added.
+   *
+   * @return $this
+   */
+  public function addCacheTags(array $cache_tags);
+
+  /**
+   * Adds the maximum age (in seconds).
+   *
+   * @param int $max_age
+   *   The max age to associate.
+   *
+   * @return $this
+   *
+   * @throws \InvalidArgumentException
+   *   If a non-integer value is supplied.
+   */
+  public function addCacheMaxAge($max_age);
+
+}
diff --git a/core/lib/Drupal/Core/Cache/MutableCacheableDependencyTrait.php b/core/lib/Drupal/Core/Cache/MutableCacheableDependencyTrait.php
new file mode 100644
index 0000000..042c7c9
--- /dev/null
+++ b/core/lib/Drupal/Core/Cache/MutableCacheableDependencyTrait.php
@@ -0,0 +1,60 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Cache\MutableCacheableDependencyTrait.
+ */
+
+namespace Drupal\Core\Cache;
+
+/**
+ * Trait for \Drupal\Core\Cache\MutableCacheableDependencyInterface.
+ */
+trait MutableCacheableDependencyTrait {
+
+  /**
+   * Runtime cache contexts.
+   *
+   * @var array
+   */
+  protected $cacheContexts = [];
+
+  /**
+   * Cache tags.
+   *
+   * @var string[]
+   */
+  protected $cacheTags = [];
+
+  /**
+   * Cache max-age.
+   *
+   * @var int
+   */
+  protected $cacheMaxAge = Cache::PERMANENT;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function addCacheContexts(array $cache_contexts) {
+    $this->cacheContexts = Cache::mergeContexts($this->cacheContexts, $cache_contexts);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function addCacheTags(array $cache_tags) {
+    $this->cacheTags = Cache::mergeTags($this->cacheTags, $cache_tags);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function addCacheMaxAge($max_age) {
+    $this->cacheMaxAge = Cache::mergeMaxAges($this->cacheMaxAge, $max_age);
+    return $this;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php
index a810dbd..c9f6502 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php
@@ -193,7 +193,7 @@ public function enable() {
    */
   public function disable() {
     // An entity was disabled, invalidate its own cache tag.
-    Cache::invalidateTags($this->getCacheTags());
+    Cache::invalidateTags($this->getCacheTagsForInvalidation());
     return $this->setStatus(FALSE);
   }
 
diff --git a/core/lib/Drupal/Core/Entity/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php
index 9ffa497..4c77b5a 100644
--- a/core/lib/Drupal/Core/Entity/Entity.php
+++ b/core/lib/Drupal/Core/Entity/Entity.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Entity;
 
 use Drupal\Core\Cache\Cache;
+use Drupal\Core\Cache\MutableCacheableDependencyTrait;
 use Drupal\Core\DependencyInjection\DependencySerializationTrait;
 use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Component\Utility\Unicode;
@@ -24,6 +25,8 @@
  */
 abstract class Entity implements EntityInterface {
 
+  use MutableCacheableDependencyTrait;
+
   use DependencySerializationTrait {
     __sleep as traitSleep;
   }
@@ -440,23 +443,36 @@ public function referencedEntities() {
    * {@inheritdoc}
    */
   public function getCacheContexts() {
-    return [];
+    return $this->cacheContexts;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function getCacheTags() {
+  public function getCacheTagsForInvalidation() {
     // @todo Add bundle-specific listing cache tag?
     //   https://www.drupal.org/node/2145751
+    if ($this->isNew()) {
+      return [];
+    }
     return [$this->entityTypeId . ':' . $this->id()];
   }
 
   /**
    * {@inheritdoc}
    */
+  public function getCacheTags() {
+    if ($this->cacheTags) {
+      return Cache::mergeTags($this->getCacheTagsForInvalidation(), $this->cacheTags);
+    }
+    return $this->getCacheTagsForInvalidation();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function getCacheMaxAge() {
-    return Cache::PERMANENT;
+    return $this->cacheMaxAge;
   }
 
   /**
@@ -511,7 +527,7 @@ protected function invalidateTagsOnSave($update) {
     }
     if ($update) {
       // An existing entity was updated, also invalidate its unique cache tag.
-      $tags = Cache::mergeTags($tags, $this->getCacheTags());
+      $tags = Cache::mergeTags($tags, $this->getCacheTagsForInvalidation());
     }
     Cache::invalidateTags($tags);
   }
@@ -532,7 +548,7 @@ protected static function invalidateTagsOnDelete(EntityTypeInterface $entity_typ
       // other pages than the one it's on. The one it's on is handled by its own
       // cache tag, but subsequent list pages would not be invalidated, hence we
       // must invalidate its list cache tags as well.)
-      $tags = Cache::mergeTags($tags, $entity->getCacheTags());
+      $tags = Cache::mergeTags($tags, $entity->getCacheTagsForInvalidation());
     }
     Cache::invalidateTags($tags);
   }
diff --git a/core/lib/Drupal/Core/Entity/EntityForm.php b/core/lib/Drupal/Core/Entity/EntityForm.php
index 6d61d0c..e5ededc 100644
--- a/core/lib/Drupal/Core/Entity/EntityForm.php
+++ b/core/lib/Drupal/Core/Entity/EntityForm.php
@@ -101,6 +101,12 @@ public function buildForm(array $form, FormStateInterface $form_state) {
       $this->init($form_state);
     }
 
+    // Ensure that edit forms have the correct cacheability metadata so they can be
+    // cached.
+    if (!$this->entity->isNew()) {
+      \Drupal::service('renderer')->addCacheableDependency($form, $this->entity);
+    }
+
     // Retrieve the form array using the possibly updated entity in form state.
     $form = $this->form($form, $form_state);
 
diff --git a/core/lib/Drupal/Core/Entity/EntityInterface.php b/core/lib/Drupal/Core/Entity/EntityInterface.php
index 68dafd0..308e16c 100644
--- a/core/lib/Drupal/Core/Entity/EntityInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityInterface.php
@@ -9,13 +9,14 @@
 
 use Drupal\Core\Access\AccessibleInterface;
 use Drupal\Core\Cache\CacheableDependencyInterface;
+use Drupal\Core\Cache\MutableCacheableDependencyInterface;
 
 /**
  * Defines a common interface for all entity objects.
  *
  * @ingroup entity_api
  */
-interface EntityInterface extends AccessibleInterface, CacheableDependencyInterface {
+interface EntityInterface extends AccessibleInterface, CacheableDependencyInterface, MutableCacheableDependencyInterface {
 
   /**
    * Gets the entity UUID (Universally Unique Identifier).
@@ -349,6 +350,14 @@ public function referencedEntities();
   public function getOriginalId();
 
   /**
+   * Returns the original cache tags of this entity, without mutations.
+   *
+   * @return string[]
+   *   List of cache tags.
+   */
+  public function getCacheTagsForInvalidation();
+
+  /**
    * Sets the original ID.
    *
    * @param int|string|null $id
diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php
index 1e1323e..933a257 100644
--- a/core/lib/Drupal/Core/Entity/EntityManager.php
+++ b/core/lib/Drupal/Core/Entity/EntityManager.php
@@ -969,6 +969,7 @@ public function getTranslationFromContext(EntityInterface $entity, $langcode = N
     if ($entity instanceof TranslatableInterface && count($entity->getTranslationLanguages()) > 1) {
       if (empty($langcode)) {
         $langcode = $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)->getId();
+        $entity->addRuntimeContexts(['languages:' . LanguageInterface::TYPE_CONTENT]);
       }
 
       // Retrieve language fallback candidates to perform the entity language
diff --git a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php
index 09736d2..8281eb9 100644
--- a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php
+++ b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php
@@ -117,14 +117,10 @@ public function view(EntityInterface $entity, $view_mode = 'full', $langcode = N
    * {@inheritdoc}
    */
   public function viewMultiple(array $entities = array(), $view_mode = 'full', $langcode = NULL) {
-    if (!isset($langcode)) {
-      $langcode = $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)->getId();
-    }
-
     $build_list = array(
       '#sorted' => TRUE,
       '#pre_render' => array(array($this, 'buildMultiple')),
-      '#langcode' => $langcode,
+      '#langcode' => $langcode ?: $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)->getId(),
     );
     $weight = 0;
     foreach ($entities as $key => $entity) {
@@ -133,9 +129,10 @@ public function viewMultiple(array $entities = array(), $view_mode = 'full', $la
       $entity = $this->entityManager->getTranslationFromContext($entity, $langcode);
 
       // Set build defaults.
-      $build_list[$key] = $this->getBuildDefaults($entity, $view_mode, $langcode);
+      $entity_langcode = $entity->language()->getId();
+      $build_list[$key] = $this->getBuildDefaults($entity, $view_mode, $entity_langcode);
       $entityType = $this->entityTypeId;
-      $this->moduleHandler()->alter(array($entityType . '_build_defaults', 'entity_build_defaults'), $build_list[$key], $entity, $view_mode, $langcode);
+      $this->moduleHandler()->alter(array($entityType . '_build_defaults', 'entity_build_defaults'), $build_list[$key], $entity, $view_mode, $entity_langcode);
 
       $build_list[$key]['#weight'] = $weight++;
     }
diff --git a/core/modules/aggregator/src/Entity/Item.php b/core/modules/aggregator/src/Entity/Item.php
index 6986aaa..b3d4af1 100644
--- a/core/modules/aggregator/src/Entity/Item.php
+++ b/core/modules/aggregator/src/Entity/Item.php
@@ -225,7 +225,7 @@ public function postSave(EntityStorageInterface $storage, $update = TRUE) {
     // handles the regular cases. The Item entity has one special case: a newly
     // created Item is *also* associated with a Feed, so we must invalidate the
     // associated Feed's cache tag.
-    Cache::invalidateTags($this->getCacheTags());
+    Cache::invalidateTags($this->getCacheTagsForInvalidation());
   }
 
   /**
diff --git a/core/modules/block/src/Entity/Block.php b/core/modules/block/src/Entity/Block.php
index 948d293..869b544 100644
--- a/core/modules/block/src/Entity/Block.php
+++ b/core/modules/block/src/Entity/Block.php
@@ -246,7 +246,7 @@ public function postSave(EntityStorageInterface $storage, $update = TRUE) {
     // so we must invalidate the associated block's cache tag (which includes
     // the theme cache tag).
     if (!$update) {
-      Cache::invalidateTags($this->getCacheTags());
+      Cache::invalidateTags($this->getCacheTagsForInvalidation());
     }
   }
 
diff --git a/core/modules/block/src/Tests/BlockViewBuilderTest.php b/core/modules/block/src/Tests/BlockViewBuilderTest.php
index ccb53e4..7d21775 100644
--- a/core/modules/block/src/Tests/BlockViewBuilderTest.php
+++ b/core/modules/block/src/Tests/BlockViewBuilderTest.php
@@ -194,7 +194,7 @@ public function testBlockViewBuilderAlter() {
 
     // Enable the block view alter hook that adds a suffix, for basic testing.
     \Drupal::state()->set('block_test_view_alter_suffix', TRUE);
-    Cache::invalidateTags($this->block->getCacheTags());
+    Cache::invalidateTags($this->block->getCacheTagsForInvalidation());
     $build = $this->getBlockRenderArray();
     $this->assertTrue(isset($build['#suffix']) && $build['#suffix'] === '<br>Goodbye!', 'A block with content is altered.');
     $this->assertIdentical($this->renderer->renderRoot($build), 'Llamas &gt; unicorns!<br>Goodbye!');
@@ -206,7 +206,7 @@ public function testBlockViewBuilderAlter() {
     $request->setMethod('GET');
 
     \Drupal::state()->set('block_test.content', NULL);
-    Cache::invalidateTags($this->block->getCacheTags());
+    Cache::invalidateTags($this->block->getCacheTagsForInvalidation());
 
     $default_keys = array('entity_view', 'block', 'test_block');
     $default_tags = array('block_view', 'config:block.block.test_block');
diff --git a/core/modules/comment/src/CommentViewBuilder.php b/core/modules/comment/src/CommentViewBuilder.php
index 6923220..66bb193 100644
--- a/core/modules/comment/src/CommentViewBuilder.php
+++ b/core/modules/comment/src/CommentViewBuilder.php
@@ -71,11 +71,9 @@ protected function getBuildDefaults(EntityInterface $entity, $view_mode, $langco
       ->getFieldDefinition($entity->getFieldName())
       ->getSetting('default_mode') === CommentManagerInterface::COMMENT_MODE_THREADED;
     // If threading is enabled, don't render cache individual comments, but do
-    // keep the cache tags, so they can bubble up.
+    // keep the cacheability metadata, so it can bubble up.
     if ($build['#comment_threaded']) {
-      $cache_tags = $build['#cache']['tags'];
-      $build['#cache'] = [];
-      $build['#cache']['tags'] = $cache_tags;
+      unset($build['#cache']['keys']);
     }
 
     return $build;
diff --git a/core/modules/comment/src/Tests/CommentTranslationUITest.php b/core/modules/comment/src/Tests/CommentTranslationUITest.php
index cfb63c8..dc1bf9e 100644
--- a/core/modules/comment/src/Tests/CommentTranslationUITest.php
+++ b/core/modules/comment/src/Tests/CommentTranslationUITest.php
@@ -33,6 +33,18 @@ class CommentTranslationUITest extends ContentTranslationUITestBase {
   protected $adminUser;
 
   /**
+   * {inheritdoc}
+   */
+  protected $defaultCacheContexts = [
+    'languages:language_interface',
+    'theme',
+    'user.permissions',
+    'timezone',
+    'url.query_args.pagers:0',
+    'user.roles'
+  ];
+
+  /**
    * Modules to install.
    *
    * @var array
diff --git a/core/modules/contact/src/Tests/Views/ContactLinkTest.php b/core/modules/contact/src/Tests/Views/ContactLinkTest.php
index 4c82d18..a4db76e 100644
--- a/core/modules/contact/src/Tests/Views/ContactLinkTest.php
+++ b/core/modules/contact/src/Tests/Views/ContactLinkTest.php
@@ -86,7 +86,7 @@ public function testContactLink() {
     // Disable contact link for no_contact.
     $this->userData->set('contact', $no_contact_account->id(), 'enabled', FALSE);
     // @todo Remove cache invalidation in https://www.drupal.org/node/2477903.
-    Cache::invalidateTags($no_contact_account->getCacheTags());
+    Cache::invalidateTags($no_contact_account->getCacheTagsForInvalidation());
     $this->drupalGet('test-contact-link');
     $this->assertContactLinks($accounts, array('root', 'admin'));
   }
diff --git a/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php b/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php
index e524359..db04c49 100644
--- a/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php
+++ b/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php
@@ -7,18 +7,22 @@
 
 namespace Drupal\content_translation\Tests;
 
+use Drupal\Core\Cache\Cache;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Language\Language;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Url;
 use Drupal\language\Entity\ConfigurableLanguage;
 use Drupal\Component\Utility\SafeMarkup;
+use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
 
 /**
  * Tests the Content Translation UI.
  */
 abstract class ContentTranslationUITestBase extends ContentTranslationTestBase {
 
+  use AssertPageCacheContextsAndTagsTrait;
+
   /**
    * The id of the entity being translated.
    *
@@ -34,6 +38,15 @@
   protected $testLanguageSelector = TRUE;
 
   /**
+   * Default cache contexts expected on a non-translated entity.
+   *
+   * Cache contexts will not be checked if this list is empty.
+   *
+   * @var string[]
+   */
+  protected $defaultCacheContexts = ['languages:language_interface', 'theme' , 'user.permissions'];
+
+  /**
    * Tests the basic translation UI.
    */
   function testTranslationUI() {
@@ -64,6 +77,11 @@ protected function doTestBasicTranslation() {
     $this->assertTrue($entity, 'Entity found in the database.');
     $this->drupalGet($entity->urlInfo());
     $this->assertResponse(200, 'Entity URL is valid.');
+
+    // Ensure that the content language cache context is not yet added to the
+    // page.
+    $this->assertCacheContexts($this->defaultCacheContexts);
+
     $this->drupalGet($entity->urlInfo('drupal:content-translation-overview'));
     $this->assertNoText('Source language', 'Source language column correctly hidden.');
 
@@ -87,9 +105,14 @@ protected function doTestBasicTranslation() {
     ], array('language' => $language));
     $this->drupalPostForm($add_url, $this->getEditValues($values, $langcode), $this->getFormSubmitActionForNewTranslation($entity, $langcode));
 
-    // Get the entity and reset its cache, so that the new translation gets the
+    // Ensure that the content language cache context is not yet added to the
+    // page.
+    $entity = entity_load($this->entityTypeId, $this->entityId, TRUE);
+    $this->drupalGet($entity->urlInfo());
+    $this->assertCacheContexts(Cache::mergeContexts(['languages:language_content'], $this->defaultCacheContexts));
+
+    // Reset the cache of the entity, so that the new translation gets the
     // updated values.
-    $entity = entity_load($this->entityTypeId, $this->entityId, TRUE);
     $metadata_source_translation = $this->manager->getTranslationMetadata($entity->getTranslation($default_langcode));
     $metadata_target_translation = $this->manager->getTranslationMetadata($entity->getTranslation($langcode));
 
diff --git a/core/modules/image/src/Entity/ImageStyle.php b/core/modules/image/src/Entity/ImageStyle.php
index a05d3a8..1ed79b6 100644
--- a/core/modules/image/src/Entity/ImageStyle.php
+++ b/core/modules/image/src/Entity/ImageStyle.php
@@ -267,7 +267,7 @@ public function flush($path = NULL) {
     // Clear caches so that formatters may be added for this style.
     drupal_theme_rebuild();
 
-    Cache::invalidateTags($this->getCacheTags());
+    Cache::invalidateTags($this->getCacheTagsForInvalidation());
 
     return $this;
   }
diff --git a/core/modules/menu_link_content/src/Tests/MenuLinkContentTranslationUITest.php b/core/modules/menu_link_content/src/Tests/MenuLinkContentTranslationUITest.php
index b068808..00604df 100644
--- a/core/modules/menu_link_content/src/Tests/MenuLinkContentTranslationUITest.php
+++ b/core/modules/menu_link_content/src/Tests/MenuLinkContentTranslationUITest.php
@@ -18,6 +18,11 @@
 class MenuLinkContentTranslationUITest extends ContentTranslationUITestBase {
 
   /**
+   * {inheritdoc}
+   */
+  protected $defaultCacheContexts = ['languages:language_interface', 'theme' , 'user.permissions', 'user.roles:authenticated'];
+
+  /**
    * Modules to enable.
    *
    * @var array
diff --git a/core/modules/node/src/Tests/NodeTranslationUITest.php b/core/modules/node/src/Tests/NodeTranslationUITest.php
index 287920b..c392750 100644
--- a/core/modules/node/src/Tests/NodeTranslationUITest.php
+++ b/core/modules/node/src/Tests/NodeTranslationUITest.php
@@ -22,6 +22,21 @@
 class NodeTranslationUITest extends ContentTranslationUITestBase {
 
   /**
+   * {inheritdoc}
+   */
+  protected $defaultCacheContexts = [
+    'languages:language_interface',
+    'theme',
+    'user.permissions',
+    'route.menu_active_trails:account',
+    'route.menu_active_trails:footer',
+    'route.menu_active_trails:main',
+    'route.menu_active_trails:tools',
+    'timezone',
+    'user.roles'
+  ];
+
+  /**
    * Modules to enable.
    *
    * @var array
diff --git a/core/modules/shortcut/src/Entity/Shortcut.php b/core/modules/shortcut/src/Entity/Shortcut.php
index a2179f9..abdc9c5 100644
--- a/core/modules/shortcut/src/Entity/Shortcut.php
+++ b/core/modules/shortcut/src/Entity/Shortcut.php
@@ -102,7 +102,7 @@ public function postSave(EntityStorageInterface $storage, $update = TRUE) {
     // newly created shortcut is *also* added to a shortcut set, so we must
     // invalidate the associated shortcut set's cache tag.
     if (!$update) {
-      Cache::invalidateTags($this->getCacheTags());
+      Cache::invalidateTags($this->getCacheTagsForInvalidation());
     }
   }
 
diff --git a/core/modules/shortcut/src/Tests/ShortcutTranslationUITest.php b/core/modules/shortcut/src/Tests/ShortcutTranslationUITest.php
index 3fc8232..580e934 100644
--- a/core/modules/shortcut/src/Tests/ShortcutTranslationUITest.php
+++ b/core/modules/shortcut/src/Tests/ShortcutTranslationUITest.php
@@ -19,6 +19,11 @@
 class ShortcutTranslationUITest extends ContentTranslationUITestBase {
 
   /**
+   * {inheritdoc}
+   */
+  protected $defaultCacheContexts = ['languages:language_interface', 'theme' , 'user'];
+
+  /**
    * Modules to enable.
    *
    * @var array
diff --git a/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php b/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php
index 0b365cb..6472cb0 100644
--- a/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php
+++ b/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php
@@ -571,7 +571,7 @@ public function testReferencedEntity() {
     // a cache miss for every route except the ones for the non-referencing
     // entity and the empty entity listing.
     $this->pass("Test invalidation of referenced entity's cache tag.", 'Debug');
-    Cache::invalidateTags($this->entity->getCacheTags());
+    Cache::invalidateTags($this->entity->getCacheTagsForInvalidation());
     $this->verifyPageCache($referencing_entity_url, 'MISS');
     $this->verifyPageCache($listing_url, 'MISS');
     $this->verifyPageCache($nonempty_entity_listing_url, 'MISS');
diff --git a/core/modules/system/src/Tests/Entity/EntityWithUriCacheTagsTestBase.php b/core/modules/system/src/Tests/Entity/EntityWithUriCacheTagsTestBase.php
index 0b6f430..5ef3660 100644
--- a/core/modules/system/src/Tests/Entity/EntityWithUriCacheTagsTestBase.php
+++ b/core/modules/system/src/Tests/Entity/EntityWithUriCacheTagsTestBase.php
@@ -121,7 +121,7 @@ public function testEntityUri() {
     // Verify that after invalidating the entity's cache tag directly, there is
     // a cache miss.
     $this->pass("Test invalidation of entity's cache tag.", 'Debug');
-    Cache::invalidateTags($this->entity->getCacheTags());
+    Cache::invalidateTags($this->entity->getCacheTagsForInvalidation());
     $this->verifyPageCache($entity_url, 'MISS');
 
     // Verify a cache hit.
diff --git a/core/modules/views/src/Plugin/views/cache/CachePluginBase.php b/core/modules/views/src/Plugin/views/cache/CachePluginBase.php
index 06a18e3..5ba6bcd 100644
--- a/core/modules/views/src/Plugin/views/cache/CachePluginBase.php
+++ b/core/modules/views/src/Plugin/views/cache/CachePluginBase.php
@@ -153,7 +153,7 @@ public function cacheGet($type) {
    * Clear out cached data for a view.
    */
   public function cacheFlush() {
-    Cache::invalidateTags($this->view->storage->getCacheTags());
+    Cache::invalidateTags($this->view->storage->getCacheTagsForInvalidation());
   }
 
   /**
diff --git a/core/modules/views/src/Tests/Plugin/CacheTagTest.php b/core/modules/views/src/Tests/Plugin/CacheTagTest.php
index 3d497d5..309a856 100644
--- a/core/modules/views/src/Tests/Plugin/CacheTagTest.php
+++ b/core/modules/views/src/Tests/Plugin/CacheTagTest.php
@@ -197,7 +197,7 @@ public function testTagCaching() {
     $view->destroy();
     // Invalidate the views cache tags in order to invalidate the render
     // caching.
-    \Drupal::service('cache_tags.invalidator')->invalidateTags($view->storage->getCacheTags());
+    \Drupal::service('cache_tags.invalidator')->invalidateTags($view->storage->getCacheTagsForInvalidation());
     $build = $view->buildRenderable();
     $renderer->renderPlain($build);
 
diff --git a/core/modules/views_ui/src/ViewUI.php b/core/modules/views_ui/src/ViewUI.php
index 05451be..32b86a6 100644
--- a/core/modules/views_ui/src/ViewUI.php
+++ b/core/modules/views_ui/src/ViewUI.php
@@ -1336,4 +1336,32 @@ public function hasTrustedData() {
     return $this->storage->hasTrustedData();
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function addCacheContexts(array $cache_contexts) {
+    return $this->storage->addCacheContexts($cache_contexts);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function addCacheMaxAge($max_age) {
+    return $this->storage->addCacheMaxAge($max_age);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheTagsForInvalidation() {
+    return $this->storage->getCacheTagsForInvalidation();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function addCacheTags(array $cache_tags) {
+    return $this->storage->addCacheTags($cache_tags);
+  }
+
 }
