diff --git a/core/modules/aggregator/config/optional/views.view.aggregator_sources.yml b/core/modules/aggregator/config/optional/views.view.aggregator_sources.yml
index cccd45b..c4d6a15 100644
--- a/core/modules/aggregator/config/optional/views.view.aggregator_sources.yml
+++ b/core/modules/aggregator/config/optional/views.view.aggregator_sources.yml
@@ -141,7 +141,7 @@ display:
       contexts:
         - 'languages:language_content'
         - 'languages:language_interface'
-      cacheable: false
+      max_age: 0
   feed_1:
     display_plugin: feed
     id: feed_1
@@ -398,7 +398,7 @@ display:
       contexts:
         - 'languages:language_content'
         - 'languages:language_interface'
-      cacheable: false
+      max_age: 0
   page_1:
     display_plugin: page
     id: page_1
@@ -418,4 +418,4 @@ display:
       contexts:
         - 'languages:language_content'
         - 'languages:language_interface'
-      cacheable: false
+      max_age: 0
diff --git a/core/modules/block_content/config/optional/views.view.block_content.yml b/core/modules/block_content/config/optional/views.view.block_content.yml
index f25b3ab..3c5eb8e 100644
--- a/core/modules/block_content/config/optional/views.view.block_content.yml
+++ b/core/modules/block_content/config/optional/views.view.block_content.yml
@@ -466,7 +466,10 @@ display:
         - 'languages:language_content'
         - 'languages:language_interface'
         - url
-      cacheable: false
+        - url.query_args
+        - user.permissions
+      max_age: 0
+      tags: {  }
   page_1:
     display_plugin: page
     id: page_1
@@ -488,4 +491,7 @@ display:
         - 'languages:language_content'
         - 'languages:language_interface'
         - url
-      cacheable: false
+        - url.query_args
+        - user.permissions
+      max_age: 0
+      tags: {  }
diff --git a/core/modules/comment/config/optional/views.view.comments_recent.yml b/core/modules/comment/config/optional/views.view.comments_recent.yml
index 5e2bb89..a62fb58 100644
--- a/core/modules/comment/config/optional/views.view.comments_recent.yml
+++ b/core/modules/comment/config/optional/views.view.comments_recent.yml
@@ -3,6 +3,7 @@ status: true
 dependencies:
   module:
     - comment
+    - node
     - user
 id: comments_recent
 label: 'Recent comments'
@@ -235,6 +236,14 @@ display:
           content: 'No comments available.'
           tokenize: false
           plugin_id: text_custom
+      display_extenders: {  }
+    cache_metadata:
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - user.permissions
+      max_age: -1
+      tags: {  }
   block_1:
     display_plugin: block
     id: block_1
@@ -245,3 +254,11 @@ display:
       block_category: 'Lists (Views)'
       allow:
         items_per_page: true
+      display_extenders: {  }
+    cache_metadata:
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - user.permissions
+      max_age: -1
+      tags: {  }
diff --git a/core/modules/comment/tests/modules/comment_test_views/test_views/views.view.test_comment_field_name.yml b/core/modules/comment/tests/modules/comment_test_views/test_views/views.view.test_comment_field_name.yml
index 9938a65..57ba803 100644
--- a/core/modules/comment/tests/modules/comment_test_views/test_views/views.view.test_comment_field_name.yml
+++ b/core/modules/comment/tests/modules/comment_test_views/test_views/views.view.test_comment_field_name.yml
@@ -200,4 +200,4 @@ display:
       contexts:
         - languages
         - user
-      cacheable: false
+      max_age: 0
diff --git a/core/modules/contact/tests/modules/contact_test_views/test_views/views.view.test_contact_link.yml b/core/modules/contact/tests/modules/contact_test_views/test_views/views.view.test_contact_link.yml
index 84b2a2b..9ba9e55 100644
--- a/core/modules/contact/tests/modules/contact_test_views/test_views/views.view.test_contact_link.yml
+++ b/core/modules/contact/tests/modules/contact_test_views/test_views/views.view.test_contact_link.yml
@@ -133,7 +133,7 @@ display:
       contexts:
         - 'languages:language_content'
         - 'languages:language_interface'
-      cacheable: false
+      max_age: 0
   page_1:
     display_plugin: page
     id: page_1
@@ -146,4 +146,4 @@ display:
       contexts:
         - 'languages:language_content'
         - 'languages:language_interface'
-      cacheable: false
+      max_age: 0
diff --git a/core/modules/entity_reference/tests/modules/entity_reference_test_views/test_views/views.view.test_entity_reference_entity_test_mul_view.yml b/core/modules/entity_reference/tests/modules/entity_reference_test_views/test_views/views.view.test_entity_reference_entity_test_mul_view.yml
index 489ea04..e95103a 100644
--- a/core/modules/entity_reference/tests/modules/entity_reference_test_views/test_views/views.view.test_entity_reference_entity_test_mul_view.yml
+++ b/core/modules/entity_reference/tests/modules/entity_reference_test_views/test_views/views.view.test_entity_reference_entity_test_mul_view.yml
@@ -117,4 +117,4 @@ display:
       contexts:
         - languages
         - 'languages:language_interface'
-      cacheable: false
+      max_age: 0
diff --git a/core/modules/entity_reference/tests/modules/entity_reference_test_views/test_views/views.view.test_entity_reference_entity_test_view.yml b/core/modules/entity_reference/tests/modules/entity_reference_test_views/test_views/views.view.test_entity_reference_entity_test_view.yml
index 291b474..d190788 100644
--- a/core/modules/entity_reference/tests/modules/entity_reference_test_views/test_views/views.view.test_entity_reference_entity_test_view.yml
+++ b/core/modules/entity_reference/tests/modules/entity_reference_test_views/test_views/views.view.test_entity_reference_entity_test_view.yml
@@ -118,4 +118,4 @@ display:
         - entity_test_view_grants
         - languages
         - 'languages:language_interface'
-      cacheable: false
+      max_age: 0
diff --git a/core/modules/entity_reference/tests/modules/entity_reference_test_views/test_views/views.view.test_entity_reference_reverse_entity_test_mul_view.yml b/core/modules/entity_reference/tests/modules/entity_reference_test_views/test_views/views.view.test_entity_reference_reverse_entity_test_mul_view.yml
index 33911a6..ff48483 100644
--- a/core/modules/entity_reference/tests/modules/entity_reference_test_views/test_views/views.view.test_entity_reference_reverse_entity_test_mul_view.yml
+++ b/core/modules/entity_reference/tests/modules/entity_reference_test_views/test_views/views.view.test_entity_reference_reverse_entity_test_mul_view.yml
@@ -127,4 +127,4 @@ display:
         - entity_test_view_grants
         - languages
         - 'languages:language_interface'
-      cacheable: false
+      max_age: 0
diff --git a/core/modules/entity_reference/tests/modules/entity_reference_test_views/test_views/views.view.test_entity_reference_reverse_entity_test_view.yml b/core/modules/entity_reference/tests/modules/entity_reference_test_views/test_views/views.view.test_entity_reference_reverse_entity_test_view.yml
index c281ef5c..6cb60b6 100644
--- a/core/modules/entity_reference/tests/modules/entity_reference_test_views/test_views/views.view.test_entity_reference_reverse_entity_test_view.yml
+++ b/core/modules/entity_reference/tests/modules/entity_reference_test_views/test_views/views.view.test_entity_reference_reverse_entity_test_view.yml
@@ -126,4 +126,4 @@ display:
       contexts:
         - languages
         - 'languages:language_interface'
-      cacheable: false
+      max_age: 0
diff --git a/core/modules/file/config/optional/views.view.files.yml b/core/modules/file/config/optional/views.view.files.yml
index 8a9cdf0..0dd0b82 100644
--- a/core/modules/file/config/optional/views.view.files.yml
+++ b/core/modules/file/config/optional/views.view.files.yml
@@ -395,8 +395,8 @@ display:
           type: boolean
           settings:
             format: custom
-            format_custom_false: 'Temporary'
-            format_custom_true: 'Permanent'
+            format_custom_false: Temporary
+            format_custom_true: Permanent
           plugin_id: field
           entity_type: file
           entity_field: status
@@ -718,9 +718,13 @@ display:
       display_extenders: {  }
     cache_metadata:
       contexts:
-        - languages
+        - 'languages:language_content'
+        - 'languages:language_interface'
         - url
-      cacheable: false
+        - url.query_args
+        - user.permissions
+      max_age: 0
+      tags: {  }
   page_1:
     display_plugin: page
     id: page_1
@@ -751,9 +755,13 @@ display:
       display_extenders: {  }
     cache_metadata:
       contexts:
-        - languages
+        - 'languages:language_content'
+        - 'languages:language_interface'
         - url
-      cacheable: false
+        - url.query_args
+        - user.permissions
+      max_age: 0
+      tags: {  }
   page_2:
     display_plugin: page
     id: page_2
@@ -1105,6 +1113,9 @@ display:
       display_extenders: {  }
     cache_metadata:
       contexts:
-        - languages
+        - 'languages:language_interface'
         - url
-      cacheable: false
+        - url.query_args
+        - user.permissions
+      max_age: 0
+      tags: {  }
diff --git a/core/modules/history/src/Plugin/views/filter/HistoryUserTimestamp.php b/core/modules/history/src/Plugin/views/filter/HistoryUserTimestamp.php
index 4117ec0..2216927 100644
--- a/core/modules/history/src/Plugin/views/filter/HistoryUserTimestamp.php
+++ b/core/modules/history/src/Plugin/views/filter/HistoryUserTimestamp.php
@@ -102,9 +102,9 @@ public function adminSummary() {
   /**
    * {@inheritdoc}
    */
-  public function isCacheable() {
+  public function getCacheMaxAge() {
     // This filter depends on the current time and therefore is never cacheable.
-    return FALSE;
+    return 0;
   }
 
 }
diff --git a/core/modules/node/config/optional/views.view.archive.yml b/core/modules/node/config/optional/views.view.archive.yml
index 56ae50e..0327679 100644
--- a/core/modules/node/config/optional/views.view.archive.yml
+++ b/core/modules/node/config/optional/views.view.archive.yml
@@ -1,8 +1,11 @@
 langcode: en
 status: false
 dependencies:
+  config:
+    - core.entity_view_mode.node.teaser
   module:
     - node
+    - user
 id: archive
 label: Archive
 module: node
@@ -166,6 +169,16 @@ display:
       empty: {  }
       relationships: {  }
       fields: {  }
+      display_extenders: {  }
+    cache_metadata:
+      contexts:
+        - 'languages:language_interface'
+        - url
+        - url.query_args
+        - 'user.node_grants:view'
+        - user.permissions
+      max_age: -1
+      tags: {  }
   block_1:
     id: block_1
     display_title: Block
@@ -195,6 +208,16 @@ display:
           specify_validation: true
           plugin_id: date_year_month
           entity_type: node
+      display_extenders: {  }
+    cache_metadata:
+      contexts:
+        - 'languages:language_interface'
+        - url
+        - url.query_args
+        - 'user.node_grants:view'
+        - user.permissions
+      max_age: -1
+      tags: {  }
   page_1:
     id: page_1
     display_title: Page
@@ -205,3 +228,13 @@ display:
         type: views_query
         options: {  }
       path: archive
+      display_extenders: {  }
+    cache_metadata:
+      contexts:
+        - 'languages:language_interface'
+        - url
+        - url.query_args
+        - 'user.node_grants:view'
+        - user.permissions
+      max_age: -1
+      tags: {  }
diff --git a/core/modules/node/config/optional/views.view.content.yml b/core/modules/node/config/optional/views.view.content.yml
index 150cf1f..58b5292 100644
--- a/core/modules/node/config/optional/views.view.content.yml
+++ b/core/modules/node/config/optional/views.view.content.yml
@@ -561,11 +561,15 @@ display:
     position: 0
     cache_metadata:
       contexts:
-        - languages
+        - 'languages:language_content'
+        - 'languages:language_interface'
         - url
+        - url.query_args
         - user
         - 'user.node_grants:view'
-      cacheable: false
+        - user.permissions
+      max_age: 0
+      tags: {  }
   page_1:
     display_options:
       path: admin/content/node
@@ -589,8 +593,12 @@ display:
     position: 1
     cache_metadata:
       contexts:
-        - languages
+        - 'languages:language_content'
+        - 'languages:language_interface'
         - url
+        - url.query_args
         - user
         - 'user.node_grants:view'
-      cacheable: false
+        - user.permissions
+      max_age: 0
+      tags: {  }
diff --git a/core/modules/node/config/optional/views.view.content_recent.yml b/core/modules/node/config/optional/views.view.content_recent.yml
index 56a425c..23f612d 100644
--- a/core/modules/node/config/optional/views.view.content_recent.yml
+++ b/core/modules/node/config/optional/views.view.content_recent.yml
@@ -296,7 +296,8 @@ display:
         - user
         - 'user.node_grants:view'
         - user.permissions
-      cacheable: false
+      max_age: 0
+      tags: {  }
   block_1:
     display_plugin: block
     id: block_1
@@ -311,4 +312,5 @@ display:
         - user
         - 'user.node_grants:view'
         - user.permissions
-      cacheable: false
+      max_age: 0
+      tags: {  }
diff --git a/core/modules/node/config/optional/views.view.frontpage.yml b/core/modules/node/config/optional/views.view.frontpage.yml
index 8b51ebb..6360665 100644
--- a/core/modules/node/config/optional/views.view.frontpage.yml
+++ b/core/modules/node/config/optional/views.view.frontpage.yml
@@ -1,6 +1,9 @@
 langcode: en
 status: true
 dependencies:
+  config:
+    - core.entity_view_mode.node.rss
+    - core.entity_view_mode.node.teaser
   module:
     - node
     - user
@@ -233,10 +236,19 @@ display:
       relationships: {  }
       fields: {  }
       arguments: {  }
+      display_extenders: {  }
     display_plugin: default
     display_title: Master
     id: default
     position: 0
+    cache_metadata:
+      contexts:
+        - 'languages:language_interface'
+        - url.query_args
+        - 'user.node_grants:view'
+        - user.permissions
+      max_age: -1
+      tags: {  }
   feed_1:
     display_plugin: feed
     id: feed_1
@@ -264,10 +276,27 @@ display:
         options:
           relationship: none
           view_mode: rss
+      display_extenders: {  }
+    cache_metadata:
+      contexts:
+        - 'languages:language_interface'
+        - 'user.node_grants:view'
+        - user.permissions
+      max_age: -1
+      tags: {  }
   page_1:
     display_options:
       path: node
+      display_extenders: {  }
     display_plugin: page
     display_title: Page
     id: page_1
     position: 1
+    cache_metadata:
+      contexts:
+        - 'languages:language_interface'
+        - url.query_args
+        - 'user.node_grants:view'
+        - user.permissions
+      max_age: -1
+      tags: {  }
diff --git a/core/modules/node/config/optional/views.view.glossary.yml b/core/modules/node/config/optional/views.view.glossary.yml
index eab49b7..9a1966b 100644
--- a/core/modules/node/config/optional/views.view.glossary.yml
+++ b/core/modules/node/config/optional/views.view.glossary.yml
@@ -346,6 +346,17 @@ display:
           plugin_id: language
           entity_type: node
           entity_field: langcode
+      display_extenders: {  }
+    cache_metadata:
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - url
+        - url.query_args
+        - 'user.node_grants:view'
+        - user.permissions
+      max_age: 0
+      tags: {  }
   attachment_1:
     id: attachment_1
     display_title: Attachment
@@ -403,6 +414,17 @@ display:
         default: default
         page_1: page_1
       inherit_arguments: false
+      display_extenders: {  }
+    cache_metadata:
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - url
+        - url.query_args
+        - 'user.node_grants:view'
+        - user.permissions
+      max_age: 0
+      tags: {  }
   page_1:
     id: page_1
     display_title: Page
@@ -419,3 +441,14 @@ display:
         weight: 0
         menu_name: main
         parent: ''
+      display_extenders: {  }
+    cache_metadata:
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - url
+        - url.query_args
+        - 'user.node_grants:view'
+        - user.permissions
+      max_age: 0
+      tags: {  }
diff --git a/core/modules/node/src/Plugin/views/argument_default/Node.php b/core/modules/node/src/Plugin/views/argument_default/Node.php
index 556b9aa..afd66da 100644
--- a/core/modules/node/src/Plugin/views/argument_default/Node.php
+++ b/core/modules/node/src/Plugin/views/argument_default/Node.php
@@ -7,8 +7,9 @@
 
 namespace Drupal\node\Plugin\views\argument_default;
 
+use Drupal\Core\Cache\Cache;
+use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
-use Drupal\views\Plugin\CacheablePluginInterface;
 use Drupal\views\Plugin\views\argument_default\ArgumentDefaultPluginBase;
 use Drupal\node\NodeInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -23,7 +24,7 @@
  *   title = @Translation("Content ID from URL")
  * )
  */
-class Node extends ArgumentDefaultPluginBase implements CacheablePluginInterface {
+class Node extends ArgumentDefaultPluginBase implements CacheableDependencyInterface {
 
   /**
    * The route match.
@@ -75,8 +76,8 @@ public function getArgument() {
   /**
    * {@inheritdoc}
    */
-  public function isCacheable() {
-    return TRUE;
+  public function getCacheMaxAge() {
+    return Cache::PERMANENT;
   }
 
   /**
@@ -86,4 +87,11 @@ public function getCacheContexts() {
     return ['url'];
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheTags() {
+    return [];
+  }
+
 }
diff --git a/core/modules/rest/src/Plugin/views/style/Serializer.php b/core/modules/rest/src/Plugin/views/style/Serializer.php
index 67a8364..ceccd61 100644
--- a/core/modules/rest/src/Plugin/views/style/Serializer.php
+++ b/core/modules/rest/src/Plugin/views/style/Serializer.php
@@ -7,8 +7,9 @@
 
 namespace Drupal\rest\Plugin\views\style;
 
+use Drupal\Core\Cache\Cache;
+use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\Form\FormStateInterface;
-use Drupal\views\Plugin\CacheablePluginInterface;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\Plugin\views\style\StylePluginBase;
@@ -27,7 +28,7 @@
  *   display_types = {"data"}
  * )
  */
-class Serializer extends StylePluginBase implements CacheablePluginInterface {
+class Serializer extends StylePluginBase implements CacheableDependencyInterface {
 
   /**
    * Overrides \Drupal\views\Plugin\views\style\StylePluginBase::$usesRowPlugin.
@@ -153,8 +154,8 @@ public function getFormats() {
   /**
    * {@inheritdoc}
    */
-  public function isCacheable() {
-    return TRUE;
+  public function getCacheMaxAge() {
+    return Cache::PERMANENT;
   }
 
   /**
@@ -164,4 +165,11 @@ public function getCacheContexts() {
     return ['request_format'];
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheTags() {
+    return [];
+  }
+
 }
diff --git a/core/modules/system/src/Plugin/views/field/BulkForm.php b/core/modules/system/src/Plugin/views/field/BulkForm.php
index 609d4c0..3a3b65c 100644
--- a/core/modules/system/src/Plugin/views/field/BulkForm.php
+++ b/core/modules/system/src/Plugin/views/field/BulkForm.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\system\Plugin\views\field;
 
+use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Entity\RevisionableInterface;
@@ -15,7 +16,6 @@
 use Drupal\Core\Routing\RedirectDestinationTrait;
 use Drupal\Core\TypedData\TranslatableInterface;
 use Drupal\views\Entity\Render\EntityTranslationRenderTrait;
-use Drupal\views\Plugin\CacheablePluginInterface;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
 use Drupal\views\Plugin\views\field\UncacheableFieldHandlerTrait;
@@ -29,7 +29,7 @@
  *
  * @ViewsField("bulk_form")
  */
-class BulkForm extends FieldPluginBase implements CacheablePluginInterface {
+class BulkForm extends FieldPluginBase implements CacheableDependencyInterface {
 
   use RedirectDestinationTrait;
   use UncacheableFieldHandlerTrait;
@@ -114,10 +114,10 @@ public function init(ViewExecutable $view, DisplayPluginBase $display, array &$o
   /**
    * {@inheritdoc}
    */
-  public function isCacheable() {
+  public function getCacheMaxAge() {
     // @todo Consider making the bulk operation form cacheable. See
     //   https://www.drupal.org/node/2503009.
-    return FALSE;
+    return 0;
   }
 
   /**
@@ -130,6 +130,13 @@ public function getCacheContexts() {
   /**
    * {@inheritdoc}
    */
+  public function getCacheTags() {
+    return [];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function getEntityTypeId() {
     return $this->getEntityType();
   }
diff --git a/core/modules/system/tests/modules/update_order_test/update_order_test.install b/core/modules/system/tests/modules/update_order_test/update_order_test.install
index b35c6f4..e969de6 100644
--- a/core/modules/system/tests/modules/update_order_test/update_order_test.install
+++ b/core/modules/system/tests/modules/update_order_test/update_order_test.install
@@ -50,4 +50,15 @@ function update_order_test_update_8002() {
     }
   }
 
+  /**
+   * Makes sure views_update_8002 runs before test update hooks.
+   */
+  function update_order_test_update_dependencies() {
+    // Run this after the views have been updated.
+    $dependencies['update_order_test'][8001] = array(
+      'views' => 8002,
+    );
+    return $dependencies;
+  }
+
 }
diff --git a/core/modules/taxonomy/config/optional/views.view.taxonomy_term.yml b/core/modules/taxonomy/config/optional/views.view.taxonomy_term.yml
index e1086d1..edbe0ae 100644
--- a/core/modules/taxonomy/config/optional/views.view.taxonomy_term.yml
+++ b/core/modules/taxonomy/config/optional/views.view.taxonomy_term.yml
@@ -246,8 +246,11 @@ display:
       contexts:
         - 'languages:language_interface'
         - url
+        - url.query_args
         - 'user.node_grants:view'
-      cacheable: false
+        - user.permissions
+      max_age: -1
+      tags: {  }
   feed_1:
     id: feed_1
     display_title: Feed
@@ -283,7 +286,9 @@ display:
         - 'languages:language_interface'
         - url
         - 'user.node_grants:view'
-      cacheable: false
+        - user.permissions
+      max_age: -1
+      tags: {  }
   page_1:
     id: page_1
     display_title: Page
@@ -299,5 +304,8 @@ display:
       contexts:
         - 'languages:language_interface'
         - url
+        - url.query_args
         - 'user.node_grants:view'
-      cacheable: false
+        - user.permissions
+      max_age: -1
+      tags: {  }
diff --git a/core/modules/taxonomy/src/Plugin/views/argument_default/Tid.php b/core/modules/taxonomy/src/Plugin/views/argument_default/Tid.php
index f162195..55cc6ef 100644
--- a/core/modules/taxonomy/src/Plugin/views/argument_default/Tid.php
+++ b/core/modules/taxonomy/src/Plugin/views/argument_default/Tid.php
@@ -7,10 +7,11 @@
 
 namespace Drupal\taxonomy\Plugin\views\argument_default;
 
+use Drupal\Core\Cache\Cache;
+use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\taxonomy\TermInterface;
-use Drupal\views\Plugin\CacheablePluginInterface;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\Plugin\views\argument_default\ArgumentDefaultPluginBase;
@@ -28,7 +29,7 @@
  *   title = @Translation("Taxonomy term ID from URL")
  * )
  */
-class Tid extends ArgumentDefaultPluginBase implements CacheablePluginInterface {
+class Tid extends ArgumentDefaultPluginBase implements CacheableDependencyInterface {
 
   /**
    * The route match.
@@ -216,8 +217,8 @@ public function getArgument() {
   /**
    * {@inheritdoc}
    */
-  public function isCacheable() {
-    return TRUE;
+  public function getCacheMaxAge() {
+    return Cache::PERMANENT;
   }
 
   /**
@@ -230,6 +231,13 @@ public function getCacheContexts() {
   /**
    * {@inheritdoc}
    */
+  public function getCacheTags() {
+    return [];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function calculateDependencies() {
     $dependencies = parent::calculateDependencies();
 
diff --git a/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.taxonomy_all_terms_test.yml b/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.taxonomy_all_terms_test.yml
index 7e2673c..fce3d6e 100644
--- a/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.taxonomy_all_terms_test.yml
+++ b/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.taxonomy_all_terms_test.yml
@@ -165,7 +165,7 @@ display:
         - 'url.query_args.pagers:0'
         - 'user.node_grants:view'
         - user.permissions
-      cacheable: false
+      max_age: 0
   page_1:
     display_plugin: page
     id: page_1
@@ -180,4 +180,4 @@ display:
         - 'url.query_args.pagers:0'
         - 'user.node_grants:view'
         - user.permissions
-      cacheable: false
+      max_age: 0
diff --git a/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_taxonomy_term_relationship.yml b/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_taxonomy_term_relationship.yml
index 22521bc..5e13b59 100644
--- a/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_taxonomy_term_relationship.yml
+++ b/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_taxonomy_term_relationship.yml
@@ -199,4 +199,4 @@ display:
       contexts:
         - 'languages:language_content'
         - 'languages:language_interface'
-      cacheable: false
+      max_age: 0
diff --git a/core/modules/user/config/optional/views.view.user_admin_people.yml b/core/modules/user/config/optional/views.view.user_admin_people.yml
index 0644e80..7973c1f 100644
--- a/core/modules/user/config/optional/views.view.user_admin_people.yml
+++ b/core/modules/user/config/optional/views.view.user_admin_people.yml
@@ -293,8 +293,8 @@ display:
           type: boolean
           settings:
             format: custom
-            format_custom_true: 'Active'
-            format_custom_false: 'Blocked'
+            format_custom_true: Active
+            format_custom_false: Blocked
           entity_type: user
           entity_field: status
         roles_target_id:
@@ -868,6 +868,15 @@ display:
         groups:
           1: AND
       display_extenders: {  }
+    cache_metadata:
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - url
+        - url.query_args
+        - user.permissions
+      max_age: 0
+      tags: {  }
   page_1:
     display_plugin: page
     id: page_1
@@ -892,3 +901,12 @@ display:
       defaults:
         show_admin_links: false
       display_extenders: {  }
+    cache_metadata:
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - url
+        - url.query_args
+        - user.permissions
+      max_age: 0
+      tags: {  }
diff --git a/core/modules/user/config/optional/views.view.who_s_new.yml b/core/modules/user/config/optional/views.view.who_s_new.yml
index dc7cde7..2d8fb9b 100644
--- a/core/modules/user/config/optional/views.view.who_s_new.yml
+++ b/core/modules/user/config/optional/views.view.who_s_new.yml
@@ -163,6 +163,14 @@ display:
       empty: {  }
       relationships: {  }
       arguments: {  }
+      display_extenders: {  }
+    cache_metadata:
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - user.permissions
+      max_age: -1
+      tags: {  }
   block_1:
     display_plugin: block
     id: block_1
@@ -172,3 +180,11 @@ display:
       display_description: 'A list of new users'
       block_description: 'Who''s new'
       block_category: User
+      display_extenders: {  }
+    cache_metadata:
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - user.permissions
+      max_age: -1
+      tags: {  }
diff --git a/core/modules/user/config/optional/views.view.who_s_online.yml b/core/modules/user/config/optional/views.view.who_s_online.yml
index e48c0d3..61af5a6 100644
--- a/core/modules/user/config/optional/views.view.who_s_online.yml
+++ b/core/modules/user/config/optional/views.view.who_s_online.yml
@@ -193,6 +193,14 @@ display:
           plugin_id: text_custom
       relationships: {  }
       arguments: {  }
+      display_extenders: {  }
+    cache_metadata:
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - user.permissions
+      max_age: -1
+      tags: {  }
   who_s_online_block:
     display_plugin: block
     id: who_s_online_block
@@ -201,3 +209,11 @@ display:
     display_options:
       block_description: 'Who''s online'
       display_description: 'A list of users that are currently logged in.'
+      display_extenders: {  }
+    cache_metadata:
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - user.permissions
+      max_age: -1
+      tags: {  }
diff --git a/core/modules/user/src/Plugin/views/access/Permission.php b/core/modules/user/src/Plugin/views/access/Permission.php
index 0dc5165..7b9f7a7 100644
--- a/core/modules/user/src/Plugin/views/access/Permission.php
+++ b/core/modules/user/src/Plugin/views/access/Permission.php
@@ -8,11 +8,12 @@
 namespace Drupal\user\Plugin\views\access;
 
 use Drupal\Component\Utility\SafeMarkup;
+use Drupal\Core\Cache\Cache;
+use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\user\PermissionHandlerInterface;
-use Drupal\views\Plugin\CacheablePluginInterface;
 use Drupal\views\Plugin\views\access\AccessPluginBase;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\Routing\Route;
@@ -28,7 +29,7 @@
  *   help = @Translation("Access will be granted to users with the specified permission string.")
  * )
  */
-class Permission extends AccessPluginBase implements CacheablePluginInterface {
+class Permission extends AccessPluginBase implements CacheableDependencyInterface {
 
   /**
    * Overrides Drupal\views\Plugin\Plugin::$usesOptions.
@@ -136,8 +137,8 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
   /**
    * {@inheritdoc}
    */
-  public function isCacheable() {
-    return TRUE;
+  public function getCacheMaxAge() {
+    return Cache::PERMANENT;
   }
 
   /**
@@ -147,4 +148,11 @@ public function getCacheContexts() {
     return ['user.permissions'];
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheTags() {
+    return [];
+  }
+
 }
diff --git a/core/modules/user/src/Plugin/views/access/Role.php b/core/modules/user/src/Plugin/views/access/Role.php
index 4c2b732..b21af04 100644
--- a/core/modules/user/src/Plugin/views/access/Role.php
+++ b/core/modules/user/src/Plugin/views/access/Role.php
@@ -8,9 +8,9 @@
 namespace Drupal\user\Plugin\views\access;
 
 use Drupal\Component\Utility\SafeMarkup;
+use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\user\RoleStorageInterface;
-use Drupal\views\Plugin\CacheablePluginInterface;
 use Drupal\views\Plugin\views\access\AccessPluginBase;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\Routing\Route;
@@ -27,7 +27,7 @@
  *   help = @Translation("Access will be granted to users with any of the specified roles.")
  * )
  */
-class Role extends AccessPluginBase implements CacheablePluginInterface {
+class Role extends AccessPluginBase implements CacheableDependencyInterface {
 
   /**
    * Overrides Drupal\views\Plugin\Plugin::$usesOptions.
@@ -149,8 +149,8 @@ public function calculateDependencies() {
   /**
    * {@inheritdoc}
    */
-  public function isCacheable() {
-    return TRUE;
+  public function getCacheMaxAge() {
+    return 0;
   }
 
   /**
@@ -160,5 +160,12 @@ public function getCacheContexts() {
     return ['user.roles'];
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheTags() {
+    return [];
+  }
+
 }
 
diff --git a/core/modules/user/src/Plugin/views/argument_default/CurrentUser.php b/core/modules/user/src/Plugin/views/argument_default/CurrentUser.php
index b3c86ec..0d435df 100644
--- a/core/modules/user/src/Plugin/views/argument_default/CurrentUser.php
+++ b/core/modules/user/src/Plugin/views/argument_default/CurrentUser.php
@@ -7,7 +7,8 @@
 
 namespace Drupal\user\Plugin\views\argument_default;
 
-use Drupal\views\Plugin\CacheablePluginInterface;
+use Drupal\Core\Cache\Cache;
+use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\views\Plugin\views\argument_default\ArgumentDefaultPluginBase;
 
 /**
@@ -20,7 +21,7 @@
  *   title = @Translation("User ID from logged in user")
  * )
  */
-class CurrentUser extends ArgumentDefaultPluginBase implements CacheablePluginInterface {
+class CurrentUser extends ArgumentDefaultPluginBase implements CacheableDependencyInterface {
 
   public function getArgument() {
     return \Drupal::currentUser()->id();
@@ -29,8 +30,8 @@ public function getArgument() {
   /**
    * {@inheritdoc}
    */
-  public function isCacheable() {
-    return TRUE;
+  public function getCacheMaxAge() {
+    return Cache::PERMANENT;
   }
 
   /**
@@ -40,4 +41,11 @@ public function getCacheContexts() {
     return ['user'];
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheTags() {
+    return [];
+  }
+
 }
diff --git a/core/modules/user/src/Plugin/views/argument_default/User.php b/core/modules/user/src/Plugin/views/argument_default/User.php
index edfb709..d50d2c0 100644
--- a/core/modules/user/src/Plugin/views/argument_default/User.php
+++ b/core/modules/user/src/Plugin/views/argument_default/User.php
@@ -7,9 +7,10 @@
 
 namespace Drupal\user\Plugin\views\argument_default;
 
+use Drupal\Core\Cache\Cache;
+use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
-use Drupal\views\Plugin\CacheablePluginInterface;
 use Drupal\views\Plugin\views\argument_default\ArgumentDefaultPluginBase;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\Request;
@@ -24,7 +25,7 @@
  *   title = @Translation("User ID from route context")
  * )
  */
-class User extends ArgumentDefaultPluginBase implements CacheablePluginInterface {
+class User extends ArgumentDefaultPluginBase implements CacheableDependencyInterface {
 
   /**
    * The route match.
@@ -108,8 +109,8 @@ public function getArgument() {
   /**
    * {@inheritdoc}
    */
-  public function isCacheable() {
-    return TRUE;
+  public function getCacheMaxAge() {
+    return Cache::PERMANENT;
   }
 
   /**
@@ -119,4 +120,11 @@ public function getCacheContexts() {
     return ['url'];
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheTags() {
+    return [];
+  }
+
 }
diff --git a/core/modules/views/config/schema/views.schema.yml b/core/modules/views/config/schema/views.schema.yml
index 7ea599d..ea1bc38 100644
--- a/core/modules/views/config/schema/views.schema.yml
+++ b/core/modules/views/config/schema/views.schema.yml
@@ -118,15 +118,19 @@ views.view.*:
             type: mapping
             label: 'Cache metadata'
             mapping:
-              cacheable:
-                type: boolean
-                label: 'Cacheable'
+              max_age:
+                type: integer
+                label: 'Cache maximum age'
               contexts:
                 type: sequence
                 label: 'Cache contexts'
                 sequence:
                   type: string
-
+              tags:
+                type: sequence
+                label: 'Cache tags'
+                sequence:
+                  type: string
 views_block:
   type: block_settings
   label: 'View block'
diff --git a/core/modules/views/src/Entity/Render/RendererBase.php b/core/modules/views/src/Entity/Render/RendererBase.php
index deb1806..19f98c3 100644
--- a/core/modules/views/src/Entity/Render/RendererBase.php
+++ b/core/modules/views/src/Entity/Render/RendererBase.php
@@ -7,9 +7,10 @@
 
 namespace Drupal\views\Entity\Render;
 
+use Drupal\Core\Cache\Cache;
+use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Language\LanguageManagerInterface;
-use Drupal\views\Plugin\CacheablePluginInterface;
 use Drupal\views\Plugin\views\query\QueryPluginBase;
 use Drupal\views\ResultRow;
 use Drupal\views\ViewExecutable;
@@ -17,7 +18,7 @@
 /**
  * Defines a base class for entity renderers.
  */
-abstract class RendererBase implements CacheablePluginInterface {
+abstract class RendererBase implements CacheableDependencyInterface {
 
   /**
    * The view executable wrapping the view storage entity.
@@ -66,8 +67,8 @@ public function __construct(ViewExecutable $view, LanguageManagerInterface $lang
   /**
    * {@inheritdoc}
    */
-  public function isCacheable() {
-    return TRUE;
+  public function getCacheMaxAge() {
+    return Cache::PERMANENT;
   }
 
   /**
@@ -78,6 +79,13 @@ public function getCacheContexts() {
   }
 
   /**
+   * {@inheritdoc}
+   */
+  public function getCacheTags() {
+    return [];
+  }
+
+  /**
    * Alters the query if needed.
    *
    * @param \Drupal\views\Plugin\views\query\QueryPluginBase $query
diff --git a/core/modules/views/src/Entity/View.php b/core/modules/views/src/Entity/View.php
index de736ec..4978ae0 100644
--- a/core/modules/views/src/Entity/View.php
+++ b/core/modules/views/src/Entity/View.php
@@ -311,8 +311,9 @@ public function preSave(EntityStorageInterface $storage) {
    *
    * Cache metadata is set per view and per display, and ends up being stored in
    * the view's configuration. This allows Views to determine very efficiently:
-   * - whether a view is cacheable at all
-   * - what the cache key for a given view should be
+   * - the max-age
+   * - the cache contexts
+   * - the cache tags
    *
    * In other words: this allows us to do the (expensive) work of initializing
    * Views plugins and handlers to determine their effect on the cacheability of
@@ -327,7 +328,10 @@ protected function addCacheMetadata() {
       $display =& $this->getDisplay($display_id);
       $executable->setDisplay($display_id);
 
-      list($display['cache_metadata']['cacheable'], $display['cache_metadata']['contexts']) = $executable->getDisplay()->calculateCacheMetadata();
+      $cache_metadata = $executable->getDisplay()->calculateCacheMetadata();
+      $display['cache_metadata']['max_age'] = $cache_metadata->getCacheMaxAge();
+      $display['cache_metadata']['contexts'] = $cache_metadata->getCacheContexts();
+      $display['cache_metadata']['tags'] = $cache_metadata->getCacheTags();
       // Always include at least the 'languages:' context as there will most
       // probably be translatable strings in the view output.
       $display['cache_metadata']['contexts'] = Cache::mergeContexts($display['cache_metadata']['contexts'], ['languages:' . LanguageInterface::TYPE_INTERFACE]);
diff --git a/core/modules/views/src/EventSubscriber/ViewsEntitySchemaSubscriber.php b/core/modules/views/src/EventSubscriber/ViewsEntitySchemaSubscriber.php
index 1904838..aa956cc 100644
--- a/core/modules/views/src/EventSubscriber/ViewsEntitySchemaSubscriber.php
+++ b/core/modules/views/src/EventSubscriber/ViewsEntitySchemaSubscriber.php
@@ -188,7 +188,11 @@ public function onEntityTypeUpdate(EntityTypeInterface $entity_type, EntityTypeI
     }
 
     foreach ($all_views as $view) {
-      $view->save();
+      // All changes done to the views here can be trusted and this might be
+      // called during updates, when it is not safe to rely on configuration
+      // containing valid schema. Trust the data and disable schema validation
+      // and casting.
+      $view->trustData()->save();
     }
   }
 
diff --git a/core/modules/views/src/Plugin/CacheablePluginInterface.php b/core/modules/views/src/Plugin/CacheablePluginInterface.php
deleted file mode 100644
index b700ce7..0000000
--- a/core/modules/views/src/Plugin/CacheablePluginInterface.php
+++ /dev/null
@@ -1,35 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\views\Plugin\CacheablePluginInterface.
- */
-
-namespace Drupal\views\Plugin;
-
-/**
- * Provides caching information about the result cacheability of views plugins.
- *
- * For caching on the render level, we rely on bubbling of the cache contexts.
- */
-interface CacheablePluginInterface {
-
-  /**
-   * Returns TRUE if this plugin is cacheable at all.
-   *
-   * @return bool
-   */
-  public function isCacheable();
-
-  /**
-   * Returns an array of cache contexts, this plugin varies by.
-   *
-   * Note: This method is called on views safe time, so you do have the
-   * configuration available. For example an exposed filter changes its
-   * cacheability depending on the URL.
-   *
-   * @return string[]
-   */
-  public function getCacheContexts();
-
-}
diff --git a/core/modules/views/src/Plugin/views/argument/ArgumentPluginBase.php b/core/modules/views/src/Plugin/views/argument/ArgumentPluginBase.php
index a1f1c5e..2737bde 100644
--- a/core/modules/views/src/Plugin/views/argument/ArgumentPluginBase.php
+++ b/core/modules/views/src/Plugin/views/argument/ArgumentPluginBase.php
@@ -11,9 +11,10 @@
 use Drupal\Component\Utility\Html;
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Component\Utility\SafeMarkup;
+use Drupal\Core\Cache\Cache;
+use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
-use Drupal\views\Plugin\CacheablePluginInterface;
 use Drupal\views\Plugin\views\PluginBase;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\ViewExecutable;
@@ -59,7 +60,7 @@
  * - numeric: If set to TRUE this field is numeric and will use %d instead of
  *            %s in queries.
  */
-abstract class ArgumentPluginBase extends HandlerBase implements CacheablePluginInterface {
+abstract class ArgumentPluginBase extends HandlerBase implements CacheableDependencyInterface {
 
   var $validator = NULL;
   var $argument = NULL;
@@ -1180,24 +1181,24 @@ protected function unpackArgumentValue($force_int = FALSE) {
   /**
    * {@inheritdoc}
    */
-  public function isCacheable() {
-    $result = TRUE;
+  public function getCacheMaxAge() {
+    $max_age = Cache::PERMANENT;
 
     // Asks all subplugins (argument defaults, argument validator and styles).
-    if (($plugin = $this->getPlugin('argument_default')) && $plugin instanceof CacheablePluginInterface) {
-      $result &= $plugin->isCacheable();
+    if (($plugin = $this->getPlugin('argument_default')) && $plugin instanceof CacheableDependencyInterface) {
+      $max_age = Cache::mergeMaxAges($max_age, $plugin->getCacheMaxAge());
     }
 
-    if (($plugin = $this->getPlugin('argument_validator')) && $plugin instanceof CacheablePluginInterface) {
-      $result &= $plugin->isCacheable();
+    if (($plugin = $this->getPlugin('argument_validator')) && $plugin instanceof CacheableDependencyInterface) {
+      $max_age = Cache::mergeMaxAges($max_age, $plugin->getCacheMaxAge());
     }
 
     // Summaries use style plugins.
-    if (($plugin = $this->getPlugin('style')) && $plugin instanceof CacheablePluginInterface) {
-      $result &= $plugin->isCacheable();
+    if (($plugin = $this->getPlugin('style')) && $plugin instanceof CacheableDependencyInterface) {
+      $max_age = Cache::mergeMaxAges($max_age, $plugin->getCacheMaxAge());
     }
 
-    return $result;
+    return $max_age;
   }
 
   /**
@@ -1211,16 +1212,16 @@ public function getCacheContexts() {
     $contexts[] = 'url';
 
     // Asks all subplugins (argument defaults, argument validator and styles).
-    if (($plugin = $this->getPlugin('argument_default')) && $plugin instanceof CacheablePluginInterface) {
-      $contexts = array_merge($plugin->getCacheContexts(), $contexts);
+    if (($plugin = $this->getPlugin('argument_default')) && $plugin instanceof CacheableDependencyInterface) {
+      $contexts = Cache::mergeContexts($contexts, $plugin->getCacheContexts());
     }
 
-    if (($plugin = $this->getPlugin('argument_validator')) && $plugin instanceof CacheablePluginInterface) {
-      $contexts = array_merge($plugin->getCacheContexts(), $contexts);
+    if (($plugin = $this->getPlugin('argument_validator')) && $plugin instanceof CacheableDependencyInterface) {
+      $contexts = Cache::mergeContexts($contexts, $plugin->getCacheContexts());
     }
 
-    if (($plugin = $this->getPlugin('style')) && $plugin instanceof CacheablePluginInterface) {
-      $contexts = array_merge($plugin->getCacheContexts(), $contexts);
+    if (($plugin = $this->getPlugin('style')) && $plugin instanceof CacheableDependencyInterface) {
+      $contexts = Cache::mergeContexts($contexts, $plugin->getCacheContexts());
     }
 
     return $contexts;
@@ -1229,6 +1230,28 @@ public function getCacheContexts() {
   /**
    * {@inheritdoc}
    */
+  public function getCacheTags() {
+    $tags = [];
+
+    // Asks all subplugins (argument defaults, argument validator and styles).
+    if (($plugin = $this->getPlugin('argument_default')) && $plugin instanceof CacheableDependencyInterface) {
+      $tags = Cache::mergeTags($tags, $plugin->getCacheTags());
+    }
+
+    if (($plugin = $this->getPlugin('argument_validator')) && $plugin instanceof CacheableDependencyInterface) {
+      $tags = Cache::mergeTags($tags, $plugin->getCacheTags());
+    }
+
+    if (($plugin = $this->getPlugin('style')) && $plugin instanceof CacheableDependencyInterface) {
+      $tags = Cache::mergeTags($tags, $plugin->getCacheTags());
+    }
+
+    return $tags;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function calculateDependencies() {
     $dependencies = [];
     if (($argument_default = $this->getPlugin('argument_default')) && $argument_default instanceof DependentPluginInterface) {
diff --git a/core/modules/views/src/Plugin/views/argument_default/Fixed.php b/core/modules/views/src/Plugin/views/argument_default/Fixed.php
index 99f55ae..43eb1f9 100644
--- a/core/modules/views/src/Plugin/views/argument_default/Fixed.php
+++ b/core/modules/views/src/Plugin/views/argument_default/Fixed.php
@@ -7,8 +7,9 @@
 
 namespace Drupal\views\Plugin\views\argument_default;
 
+use Drupal\Core\Cache\Cache;
+use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\Form\FormStateInterface;
-use Drupal\views\Plugin\CacheablePluginInterface;
 
 /**
  * The fixed argument default handler.
@@ -20,7 +21,7 @@
  *   title = @Translation("Fixed")
  * )
  */
-class Fixed extends ArgumentDefaultPluginBase implements CacheablePluginInterface {
+class Fixed extends ArgumentDefaultPluginBase implements CacheableDependencyInterface {
 
   protected function defineOptions() {
     $options = parent::defineOptions();
@@ -48,8 +49,8 @@ public function getArgument() {
   /**
    * {@inheritdoc}
    */
-  public function isCacheable() {
-    return TRUE;
+  public function getCacheMaxAge() {
+    return Cache::PERMANENT;
   }
 
   /**
@@ -59,4 +60,11 @@ public function getCacheContexts() {
     return [];
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheTags() {
+    return [];
+  }
+
 }
diff --git a/core/modules/views/src/Plugin/views/argument_default/QueryParameter.php b/core/modules/views/src/Plugin/views/argument_default/QueryParameter.php
index feccd21..f4bf3f4 100644
--- a/core/modules/views/src/Plugin/views/argument_default/QueryParameter.php
+++ b/core/modules/views/src/Plugin/views/argument_default/QueryParameter.php
@@ -7,8 +7,9 @@
 
 namespace Drupal\views\Plugin\views\argument_default;
 
+use Drupal\Core\Cache\Cache;
+use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\Form\FormStateInterface;
-use Drupal\views\Plugin\CacheablePluginInterface;
 
 /**
  * A query parameter argument default handler.
@@ -20,7 +21,7 @@
  *   title = @Translation("Query parameter")
  * )
  */
-class QueryParameter extends ArgumentDefaultPluginBase implements CacheablePluginInterface {
+class QueryParameter extends ArgumentDefaultPluginBase implements CacheableDependencyInterface {
 
   /**
    * {@inheritdoc}
@@ -87,8 +88,8 @@ public function getArgument() {
   /**
    * {@inheritdoc}
    */
-  public function isCacheable() {
-    return TRUE;
+  public function getCacheMaxAge() {
+    return Cache::PERMANENT;
   }
 
   /**
@@ -98,4 +99,11 @@ public function getCacheContexts() {
     return ['url'];
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheTags() {
+    return [];
+  }
+
 }
diff --git a/core/modules/views/src/Plugin/views/argument_default/Raw.php b/core/modules/views/src/Plugin/views/argument_default/Raw.php
index 20715f3..bb88532 100644
--- a/core/modules/views/src/Plugin/views/argument_default/Raw.php
+++ b/core/modules/views/src/Plugin/views/argument_default/Raw.php
@@ -7,10 +7,11 @@
 
 namespace Drupal\views\Plugin\views\argument_default;
 
+use Drupal\Core\Cache\Cache;
+use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Path\AliasManagerInterface;
 use Drupal\Core\Path\CurrentPathStack;
-use Drupal\views\Plugin\CacheablePluginInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\Request;
 
@@ -24,7 +25,7 @@
  *   title = @Translation("Raw value from URL")
  * )
  */
-class Raw extends ArgumentDefaultPluginBase implements CacheablePluginInterface {
+class Raw extends ArgumentDefaultPluginBase implements CacheableDependencyInterface {
 
   /**
    * The alias manager.
@@ -116,8 +117,8 @@ public function getArgument() {
   /**
    * {@inheritdoc}
    */
-  public function isCacheable() {
-    return TRUE;
+  public function getCacheMaxAge() {
+    return Cache::PERMANENT;
   }
 
   /**
@@ -127,4 +128,11 @@ public function getCacheContexts() {
     return ['url'];
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheTags() {
+    return [];
+  }
+
 }
diff --git a/core/modules/views/src/Plugin/views/cache/CachePluginBase.php b/core/modules/views/src/Plugin/views/cache/CachePluginBase.php
index 3a38dd0..9b31126 100644
--- a/core/modules/views/src/Plugin/views/cache/CachePluginBase.php
+++ b/core/modules/views/src/Plugin/views/cache/CachePluginBase.php
@@ -8,6 +8,7 @@
 namespace Drupal\views\Plugin\views\cache;
 
 use Drupal\Core\Cache\Cache;
+use Drupal\Core\Cache\CacheableMetadata;
 use Drupal\views\Plugin\views\PluginBase;
 use Drupal\Core\Database\Query\Select;
 use Drupal\views\ResultRow;
@@ -211,7 +212,7 @@ public function generateResultsKey() {
         'items_per_page' => $this->view->getItemsPerPage(),
         'offset' => $this->view->getOffset(),
       ];
-      $key_data += \Drupal::service('cache_contexts_manager')->convertTokensToKeys($this->displayHandler->getCacheMetadata()['contexts'])->getKeys();
+      $key_data += \Drupal::service('cache_contexts_manager')->convertTokensToKeys($this->displayHandler->getCacheMetadata()->getCacheContexts())->getKeys();
 
       $this->resultsKey = $this->view->storage->id() . ':' . $this->displayHandler->display['id'] . ':results:' . hash('sha256', serialize($key_data));
     }
@@ -288,12 +289,10 @@ protected function prepareViewResult(array $result) {
   /**
    * Alters the cache metadata of a display upon saving a view.
    *
-   * @param bool $is_cacheable
-   *   Whether the display is cacheable.
-   * @param string[] $cache_contexts
-   *   The cache contexts the display varies by.
+   * @param \Drupal\Core\Cache\CacheableMetadata $cache_metadata
+   *   The cache metadata.
    */
-  public function alterCacheMetadata(&$is_cacheable, array &$cache_contexts) {
+  public function alterCacheMetadata(CacheableMetadata $cache_metadata) {
   }
 
   /**
diff --git a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
index f9ae57a..d64949a 100644
--- a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
+++ b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
@@ -13,6 +13,7 @@
 use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Cache\CacheableMetadata;
+use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Plugin\PluginDependencyTrait;
@@ -20,7 +21,6 @@
 use Drupal\Core\Theme\Registry;
 use Drupal\Core\Url;
 use Drupal\views\Form\ViewsForm;
-use Drupal\views\Plugin\CacheablePluginInterface;
 use Drupal\views\Plugin\views\area\AreaPluginBase;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\PluginBase;
@@ -2144,9 +2144,9 @@ protected function applyDisplayCachablityMetadata(array &$element) {
     $cache = $this->getPlugin('cache');
 
     (new CacheableMetadata())
-      ->setCacheTags($this->view->getCacheTags())
+      ->setCacheTags(Cache::mergeTags($this->view->getCacheTags(), isset($this->display['cache_metadata']['tags']) ? $this->display['cache_metadata']['tags'] : []))
       ->setCacheContexts(isset($this->display['cache_metadata']['contexts']) ? $this->display['cache_metadata']['contexts'] : [])
-      ->setCacheMaxAge($cache->getCacheMaxAge())
+      ->setCacheMaxAge(Cache::mergeMaxAges($cache->getCacheMaxAge(), isset($this->display['cache_metadata']['max_age']) ? $this->display['cache_metadata']['max_age'] : Cache::PERMANENT))
       ->merge(CacheableMetadata::createFromRenderArray($element))
       ->applyTo($element);
   }
@@ -2264,18 +2264,13 @@ public function preExecute() {
    * {@inheritdoc}
    */
   public function calculateCacheMetadata () {
-    $is_cacheable = TRUE;
-    $cache_contexts = [];
+    $cache_metadata = new CacheableMetadata();
 
     // Iterate over ordinary views plugins.
     foreach (Views::getPluginTypes('plugin') as $plugin_type) {
       $plugin = $this->getPlugin($plugin_type);
-      if ($plugin instanceof CacheablePluginInterface) {
-        $cache_contexts = array_merge($cache_contexts, $plugin->getCacheContexts());
-        $is_cacheable &= $plugin->isCacheable();
-      }
-      else {
-        $is_cacheable = FALSE;
+      if ($plugin instanceof CacheableDependencyInterface) {
+        $cache_metadata = $cache_metadata->merge(CacheableMetadata::createFromObject($plugin));
       }
     }
 
@@ -2284,29 +2279,37 @@ public function calculateCacheMetadata () {
     foreach (array_keys(Views::getHandlerTypes()) as $handler_type) {
       $handlers = $this->getHandlers($handler_type);
       foreach ($handlers as $handler) {
-        if ($handler instanceof CacheablePluginInterface) {
-          $cache_contexts = array_merge($cache_contexts, $handler->getCacheContexts());
-          $is_cacheable &= $handler->isCacheable();
+        if ($handler instanceof CacheableDependencyInterface) {
+          $cache_metadata = $cache_metadata->merge(CacheableMetadata::createFromObject($handler));
         }
       }
     }
 
     /** @var \Drupal\views\Plugin\views\cache\CachePluginBase $cache_plugin */
     if ($cache_plugin = $this->getPlugin('cache')) {
-      $cache_plugin->alterCacheMetadata($is_cacheable, $cache_contexts);
+      $cache_plugin->alterCacheMetadata($cache_metadata);
     }
 
-    return [(bool) $is_cacheable, $cache_contexts];
+    return $cache_metadata;
   }
 
   /**
    * {@inheritdoc}
    */
   public function getCacheMetadata() {
-    if (!isset($this->display['cache_metadata'])) {
-      list($this->display['cache_metadata']['cacheable'], $this->display['cache_metadata']['contexts']) = $this->calculateCacheMetadata();
+    if (!isset($this->display['cache_metadata']['max_age']) || !isset($this->display['cache_metadata']['contexts']) || !isset($this->display['cache_metadata']['tags'])) {
+      $cache_metadata = $this->calculateCacheMetadata();
+      $this->display['cache_metadata']['max_age'] = $cache_metadata->getCacheMaxAge();
+      $this->display['cache_metadata']['contexts'] = $cache_metadata->getCacheContexts();
+      $this->display['cache_metadata']['tags'] = $cache_metadata->getCacheTags();
     }
-    return $this->display['cache_metadata'];
+    else {
+      $cache_metadata = (new CacheableMetadata())
+        ->setCacheMaxAge($this->display['cache_metadata']['max_age'])
+        ->setCacheContexts($this->display['cache_metadata']['contexts'])
+        ->setCacheTags($this->display['cache_metadata']['tags']);
+    }
+    return $cache_metadata;
   }
 
   /**
diff --git a/core/modules/views/src/Plugin/views/display/DisplayPluginInterface.php b/core/modules/views/src/Plugin/views/display/DisplayPluginInterface.php
index 780073b..666ed52 100644
--- a/core/modules/views/src/Plugin/views/display/DisplayPluginInterface.php
+++ b/core/modules/views/src/Plugin/views/display/DisplayPluginInterface.php
@@ -429,20 +429,16 @@ public function preExecute();
   /**
    * Calculates the display's cache metadata by inspecting each handler/plugin.
    *
-   * @return array
-   *   Returns an array:
-   *   - first value: (boolean) Whether the display is cacheable.
-   *   - second value: (string[]) The cache contexts the display varies by.
+   * @return \Drupal\Core\Cache\CacheableMetadata
+   *   The cache metadata.
    */
   public function calculateCacheMetadata();
 
   /**
    * Gets the cache metadata.
    *
-   * @return array
-   *   Returns an array:
-   *   - first value: (boolean) Whether the display is cacheable.
-   *   - second value: (string[]) The cache contexts the display varies by.
+   * @return \Drupal\Core\Cache\CacheableMetadata
+   *   The cache metadata.
    */
   public function getCacheMetadata();
 
diff --git a/core/modules/views/src/Plugin/views/exposed_form/ExposedFormPluginBase.php b/core/modules/views/src/Plugin/views/exposed_form/ExposedFormPluginBase.php
index d17f70c..9bc56cd 100644
--- a/core/modules/views/src/Plugin/views/exposed_form/ExposedFormPluginBase.php
+++ b/core/modules/views/src/Plugin/views/exposed_form/ExposedFormPluginBase.php
@@ -8,10 +8,11 @@
 namespace Drupal\views\Plugin\views\exposed_form;
 
 use Drupal\Component\Utility\SafeMarkup;
+use Drupal\Core\Cache\Cache;
+use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\Form\FormState;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Form\ViewsExposedForm;
-use Drupal\views\Plugin\CacheablePluginInterface;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\Plugin\views\PluginBase;
@@ -35,7 +36,7 @@
 /**
  * Base class for Views exposed filter form plugins.
  */
-abstract class ExposedFormPluginBase extends PluginBase implements CacheablePluginInterface {
+abstract class ExposedFormPluginBase extends PluginBase implements CacheableDependencyInterface {
 
   /**
    * Overrides Drupal\views\Plugin\Plugin::$usesOptions.
@@ -336,8 +337,8 @@ public function resetForm(&$form, FormStateInterface $form_state) {
   /**
    * {@inheritdoc}
    */
-  public function isCacheable() {
-    return TRUE;
+  public function getCacheMaxAge() {
+    return Cache::PERMANENT;
   }
 
   /**
@@ -364,6 +365,13 @@ public function getCacheContexts() {
     return $contexts;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheTags() {
+    return [];
+  }
+
 }
 
 /**
diff --git a/core/modules/views/src/Plugin/views/field/Field.php b/core/modules/views/src/Plugin/views/field/Field.php
index 251d025..82cf23d 100644
--- a/core/modules/views/src/Plugin/views/field/Field.php
+++ b/core/modules/views/src/Plugin/views/field/Field.php
@@ -8,6 +8,8 @@
 namespace Drupal\views\Plugin\views\field;
 
 use Drupal\Component\Utility\Xss as CoreXss;
+use Drupal\Core\Cache\Cache;
+use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
@@ -22,7 +24,6 @@
 use Drupal\Core\Session\AccountInterface;
 use Drupal\views\FieldAPIHandlerTrait;
 use Drupal\views\Entity\Render\EntityFieldRenderer;
-use Drupal\views\Plugin\CacheablePluginInterface;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\ResultRow;
 use Drupal\views\ViewExecutable;
@@ -37,7 +38,7 @@
  *
  * @ViewsField("field")
  */
-class Field extends FieldPluginBase implements CacheablePluginInterface, MultiItemsFieldHandlerInterface {
+class Field extends FieldPluginBase implements CacheableDependencyInterface, MultiItemsFieldHandlerInterface {
   use FieldAPIHandlerTrait;
 
   /**
@@ -951,8 +952,8 @@ public function calculateDependencies() {
   /**
    * {@inheritdoc}
    */
-  public function isCacheable() {
-    return FALSE;
+  public function getCacheMaxAge() {
+    return Cache::PERMANENT;
   }
 
   /**
@@ -963,6 +964,18 @@ public function getCacheContexts() {
   }
 
   /**
+   * {@inheritdoc}
+   */
+  public function getCacheTags() {
+    $field_definition = $this->getFieldDefinition();
+    $field_storage_definition = $this->getFieldStorageDefinition();
+    return Cache::mergeTags(
+      $field_definition instanceof CacheableDependencyInterface ? $field_definition->getCacheTags() : [],
+      $field_storage_definition instanceof CacheableDependencyInterface ? $field_storage_definition->getCacheTags() : []
+    );
+  }
+
+  /**
    * Gets the table mapping for the entity type of the field.
    *
    * @return \Drupal\Core\Entity\Sql\DefaultTableMapping
diff --git a/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php b/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
index d2e9fe8..ee383b1 100644
--- a/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
+++ b/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
@@ -7,11 +7,12 @@
 
 namespace Drupal\views\Plugin\views\filter;
 
+use Drupal\Core\Cache\Cache;
+use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\Form\FormHelper;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
 use Drupal\user\RoleInterface;
-use Drupal\views\Plugin\CacheablePluginInterface;
 use Drupal\views\Plugin\views\HandlerBase;
 use Drupal\Component\Utility\Html;
 use Drupal\Component\Utility\SafeMarkup;
@@ -47,7 +48,7 @@
 /**
  * Base class for Views filters handler plugins.
  */
-abstract class FilterPluginBase extends HandlerBase implements CacheablePluginInterface {
+abstract class FilterPluginBase extends HandlerBase implements CacheableDependencyInterface {
 
   /**
    * Contains the actual value of the field,either configured in the views ui
@@ -1465,8 +1466,8 @@ protected static function arrayFilterZero($var) {
   /**
    * {@inheritdoc}
    */
-  public function isCacheable() {
-    return TRUE;
+  public function getCacheMaxAge() {
+    return Cache::PERMANENT;
   }
 
   /**
@@ -1483,6 +1484,13 @@ public function getCacheContexts() {
     return $cache_contexts;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheTags() {
+    return [];
+  }
+
 }
 
 /**
diff --git a/core/modules/views/src/Plugin/views/pager/SqlBase.php b/core/modules/views/src/Plugin/views/pager/SqlBase.php
index 4262701..fb590e6 100644
--- a/core/modules/views/src/Plugin/views/pager/SqlBase.php
+++ b/core/modules/views/src/Plugin/views/pager/SqlBase.php
@@ -7,13 +7,14 @@
 
 namespace Drupal\views\Plugin\views\pager;
 
+use Drupal\Core\Cache\Cache;
+use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\Form\FormStateInterface;
-use Drupal\views\Plugin\CacheablePluginInterface;
 
 /**
  * A common base class for sql based pager.
  */
-abstract class SqlBase extends PagerPluginBase implements CacheablePluginInterface {
+abstract class SqlBase extends PagerPluginBase implements CacheableDependencyInterface {
 
   protected function defineOptions() {
     $options = parent::defineOptions();
@@ -374,8 +375,8 @@ public function exposedFormValidate(&$form, FormStateInterface $form_state) {
   /**
    * {@inheritdoc}
    */
-  public function isCacheable() {
-    return TRUE;
+  public function getCacheMaxAge() {
+    return Cache::PERMANENT;
   }
 
   /**
@@ -387,4 +388,11 @@ public function getCacheContexts() {
     return ['url.query_args'];
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheTags() {
+    return [];
+  }
+
 }
diff --git a/core/modules/views/src/Plugin/views/query/QueryPluginBase.php b/core/modules/views/src/Plugin/views/query/QueryPluginBase.php
index 97498e9..ef77f35 100644
--- a/core/modules/views/src/Plugin/views/query/QueryPluginBase.php
+++ b/core/modules/views/src/Plugin/views/query/QueryPluginBase.php
@@ -8,8 +8,8 @@
 namespace Drupal\views\Plugin\views\query;
 
 use Drupal\Core\Cache\Cache;
+use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\Form\FormStateInterface;
-use Drupal\views\Plugin\CacheablePluginInterface;
 use Drupal\views\Plugin\views\PluginBase;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\ViewExecutable;
@@ -37,7 +37,7 @@
 /**
  * Base plugin class for Views queries.
  */
-abstract class QueryPluginBase extends PluginBase implements CacheablePluginInterface {
+abstract class QueryPluginBase extends PluginBase implements CacheableDependencyInterface {
 
   /**
    * A pager plugin that should be provided by the display.
@@ -320,9 +320,9 @@ public function getEntityTableInfo() {
   /**
    * {@inheritdoc}
    */
-  public function isCacheable() {
+  public function getCacheMaxAge() {
     // This plugin can't really determine that.
-    return TRUE;
+    return Cache::PERMANENT;
   }
 
   /**
@@ -345,13 +345,6 @@ public function getCacheTags() {
     return [];
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function getCacheMaxAge() {
-    return Cache::PERMANENT;
-  }
-
 }
 
 /**
diff --git a/core/modules/views/src/Plugin/views/sort/Random.php b/core/modules/views/src/Plugin/views/sort/Random.php
index 9d8fdbb..944ac7f 100644
--- a/core/modules/views/src/Plugin/views/sort/Random.php
+++ b/core/modules/views/src/Plugin/views/sort/Random.php
@@ -7,15 +7,15 @@
 
 namespace Drupal\views\Plugin\views\sort;
 
+use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\Form\FormStateInterface;
-use Drupal\views\Plugin\CacheablePluginInterface;
 
 /**
  * Handle a random sort.
  *
  * @ViewsSort("random")
  */
-class Random extends SortPluginBase implements CacheablePluginInterface {
+class Random extends SortPluginBase implements CacheableDependencyInterface {
 
   /**
    * {@inheritdoc}
@@ -26,8 +26,6 @@ public function usesGroupBy() {
 
   public function query() {
     $this->query->addOrderBy('rand');
-    // @todo Replace this once https://www.drupal.org/node/2464427 is in.
-    $this->view->element['#cache']['max-age'] = 0;
   }
 
   public function buildOptionsForm(&$form, FormStateInterface $form_state) {
@@ -38,8 +36,8 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
   /**
    * {@inheritdoc}
    */
-  public function isCacheable() {
-    return FALSE;
+  public function getCacheMaxAge() {
+    return 0;
   }
 
   /**
@@ -49,4 +47,11 @@ public function getCacheContexts() {
     return [];
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheTags() {
+    return [];
+  }
+
 }
diff --git a/core/modules/views/src/Plugin/views/sort/SortPluginBase.php b/core/modules/views/src/Plugin/views/sort/SortPluginBase.php
index 98f3797..f2742be 100644
--- a/core/modules/views/src/Plugin/views/sort/SortPluginBase.php
+++ b/core/modules/views/src/Plugin/views/sort/SortPluginBase.php
@@ -7,8 +7,9 @@
 
 namespace Drupal\views\Plugin\views\sort;
 
+use Drupal\Core\Cache\Cache;
+use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\Form\FormStateInterface;
-use Drupal\views\Plugin\CacheablePluginInterface;
 use Drupal\views\Plugin\views\HandlerBase;
 
 /**
@@ -27,7 +28,7 @@
 /**
  * Base sort handler that has no options and performs a simple sort.
  */
-abstract class SortPluginBase extends HandlerBase implements CacheablePluginInterface {
+abstract class SortPluginBase extends HandlerBase implements CacheableDependencyInterface {
 
   /**
    * Determine if a sort can be exposed.
@@ -228,10 +229,10 @@ public function defaultExposeOptions() {
   /**
    * {@inheritdoc}
    */
-  public function isCacheable() {
+  public function getCacheMaxAge() {
     // The result of a sort does not depend on outside information, so by
     // default it is cacheable.
-    return TRUE;
+    return Cache::PERMANENT;
   }
 
   /**
@@ -246,6 +247,13 @@ public function getCacheContexts() {
     return $cache_contexts;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheTags() {
+    return [];
+  }
+
 }
 
 /**
diff --git a/core/modules/views/src/Plugin/views/style/Table.php b/core/modules/views/src/Plugin/views/style/Table.php
index 8a594cf..e58242a 100644
--- a/core/modules/views/src/Plugin/views/style/Table.php
+++ b/core/modules/views/src/Plugin/views/style/Table.php
@@ -9,8 +9,8 @@
 
 use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
 use Drupal\Component\Utility\Html;
+use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\Form\FormStateInterface;
-use Drupal\views\Plugin\CacheablePluginInterface;
 use Drupal\views\Plugin\views\wizard\WizardInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\Request;
@@ -28,7 +28,7 @@
  *   display_types = {"normal"}
  * )
  */
-class Table extends StylePluginBase implements CacheablePluginInterface {
+class Table extends StylePluginBase implements CacheableDependencyInterface {
 
   /**
    * Does the style plugin for itself support to add fields to it's output.
@@ -432,8 +432,8 @@ public function wizardSubmit(&$form, FormStateInterface $form_state, WizardInter
   /**
    * {@inheritdoc}
    */
-  public function isCacheable() {
-    return TRUE;
+  public function getCacheMaxAge() {
+    return 0;
   }
 
   /**
@@ -454,4 +454,11 @@ public function getCacheContexts() {
     return $contexts;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheTags() {
+    return [];
+  }
+
 }
diff --git a/core/modules/views/src/Tests/GlossaryTest.php b/core/modules/views/src/Tests/GlossaryTest.php
index d5a6aae..d79b183 100644
--- a/core/modules/views/src/Tests/GlossaryTest.php
+++ b/core/modules/views/src/Tests/GlossaryTest.php
@@ -85,7 +85,18 @@ public function testGlossaryView() {
       ],
       [
         'config:views.view.glossary',
+        // Listed for letter 'a'
         'node:' . $nodes_by_char['a'][0]->id(), 'node:' . $nodes_by_char['a'][1]->id(), 'node:' . $nodes_by_char['a'][2]->id(),
+        // Link for letter 'd'.
+        'node:1',
+        // Link for letter 'p'.
+        'node:16',
+        // Link for letter 'r'.
+        'node:2',
+        // Link for letter 'l'.
+        'node:21',
+        // Link for letter 'u'.
+        'node:6',
         'node_list',
         'user:0',
         'user_list',
diff --git a/core/modules/views/src/Tests/Update/CacheabilityMetadataUpdateTest.php b/core/modules/views/src/Tests/Update/CacheabilityMetadataUpdateTest.php
new file mode 100644
index 0000000..bcf4773
--- /dev/null
+++ b/core/modules/views/src/Tests/Update/CacheabilityMetadataUpdateTest.php
@@ -0,0 +1,58 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views\Tests\Update\CacheabilityMetadataUpdateTest.
+ */
+
+namespace Drupal\views\Tests\Update;
+
+use Drupal\system\Tests\Update\UpdatePathTestBase;
+use Drupal\views\Views;
+
+/**
+ * Tests that views update hooks are properly run.
+ *
+ * @see views_update_8002().
+ *
+ * @group Update
+ */
+class CacheabilityMetadataUpdateTest extends UpdatePathTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    $this->databaseDumpFiles = [__DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz'];
+    parent::setUp();
+  }
+
+  /**
+   * Tests that views cacheability metadata updated properly.
+   */
+  public function testUpdateHookN() {
+    // Verify that the 8001 schema is in place.
+    $this->assertEqual(drupal_get_installed_schema_version('views'), 8000);
+    foreach (Views::getAllViews() as $view) {
+      $displays = $view->get('display');
+      foreach (array_keys($displays) as $display_id) {
+        $display = $view->getDisplay($display_id);
+        $this->assertTrue(isset($display['cache_metadata']['cacheable']));
+      }
+    }
+    $this->runUpdates();
+    // Ensure schema has changed.
+    $this->assertEqual(drupal_get_installed_schema_version('views', TRUE), 8002);
+    foreach (Views::getAllViews() as $view) {
+      $displays = $view->get('display');
+      foreach (array_keys($displays) as $display_id) {
+        $display = $view->getDisplay($display_id);
+        $this->assertFalse(isset($display['cache_metadata']['cacheable']));
+        $this->assertTrue(isset($display['cache_metadata']['contexts']));
+        $this->assertTrue(isset($display['cache_metadata']['max_age']));
+        $this->assertTrue(isset($display['cache_metadata']['tags']));
+      }
+    }
+  }
+
+}
diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.numeric_test.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.numeric_test.yml
index 8593665..7bcc16b 100644
--- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.numeric_test.yml
+++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.numeric_test.yml
@@ -174,7 +174,7 @@ display:
     cache_metadata:
       contexts:
         - language
-      cacheable: false
+      max_age: 0
   page_1:
     display_plugin: page
     id: page_1
@@ -186,4 +186,4 @@ display:
     cache_metadata:
       contexts:
         - language
-      cacheable: false
+      max_age: 0
diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_test_link.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_test_link.yml
index 509826c..e2a148c 100644
--- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_test_link.yml
+++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_test_link.yml
@@ -323,4 +323,4 @@ display:
         - entity_test_view_grants
         - 'languages:language_content'
         - 'languages:language_interface'
-      cacheable: false
+      max_age: 0
diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_feed_icon.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_feed_icon.yml
index a5bb9f5..b0087c7 100644
--- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_feed_icon.yml
+++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_feed_icon.yml
@@ -174,7 +174,7 @@ display:
         - 'languages:language_interface'
         - url
         - 'user.node_grants:view'
-      cacheable: false
+      max_age: 0
   feed_1:
     display_plugin: feed
     id: feed_1
@@ -198,7 +198,7 @@ display:
         - 'languages:language_interface'
         - url
         - 'user.node_grants:view'
-      cacheable: false
+      max_age: 0
   page_1:
     display_plugin: page
     id: page_1
@@ -213,4 +213,4 @@ display:
         - 'languages:language_interface'
         - url
         - 'user.node_grants:view'
-      cacheable: false
+      max_age: 0
diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_field_field_attachment_test.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_field_field_attachment_test.yml
index eae936f..eeb345e 100644
--- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_field_field_attachment_test.yml
+++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_field_field_attachment_test.yml
@@ -137,4 +137,4 @@ display:
       contexts:
         - 'languages:language_content'
         - 'languages:language_interface'
-      cacheable: false
+      max_age: 0
diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_row_render_cache.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_row_render_cache.yml
index 28a1812..aed7b54 100644
--- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_row_render_cache.yml
+++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_row_render_cache.yml
@@ -500,4 +500,4 @@ display:
         - 'languages:language_content'
         - 'languages:language_interface'
         - 'user.node_grants:view'
-      cacheable: false
+      max_age: 0
diff --git a/core/modules/views/views.install b/core/modules/views/views.install
index 5615747..adfd750 100644
--- a/core/modules/views/views.install
+++ b/core/modules/views/views.install
@@ -110,12 +110,55 @@ function views_update_8001(&$sandbox) {
   }
 
   if (!empty($ids)) {
-    $message = \Drupal::translation()->translate('Updated field plugins for views: @ids', ['@ids' => implode(', ', array_unique($ids))]);
+    $message = t('Updated field plugins for views: @ids', ['@ids' => implode(', ', array_unique($ids))]);
   }
 
   return $message;
 }
 
 /**
+ * Update all views to re-generate the cacheability metadata.
+ */
+function views_update_8002(&$sandbox) {
+  $config_factory = \Drupal::configFactory();
+
+  // Remove 'cacheable' key from cache_metadata. See change record
+  // https://www.drupal.org/node/2538352 for more explanation.
+  foreach ($config_factory->listAll('views.view.') as $view_config_name) {
+    $view = $config_factory->getEditable($view_config_name);
+    // To update the cacheability metadata of an existing view we have to
+    // recalculate it. Cacheability metadata is calculated per display bases so
+    // we have to load each display. To load the each display we need
+    // \Drupal\views\ViewExecutable. To load the ViewExecutable we need
+    // \Drupal\views\ViewEntityInterface which can be loaded using views storage
+    // controller.
+    /*  @var \Drupal\views\ViewEntityInterface $view_storage */
+    $view_storage = \Drupal::service('entity.manager')
+      ->getStorage('view')
+      ->load($view->get('id'));
+    $view_executable = \Drupal::service('views.executable')
+      ->get($view_storage);
+    $displays = $view->get('display');
+    foreach (array_keys($displays) as $display_id) {
+      $view_executable->setDisplay($display_id);
+      $display_plugin = $view_executable
+        ->getDisplay();
+      // Remove the old cacheability metadata so that we can recalculate.
+      unset($display_plugin->display['cache_metadata']);
+      $cache_metadata = $display_plugin->getCacheMetadata();
+      $view->set("display.$display_id.cache_metadata", [
+        'contexts' => $cache_metadata->getCacheContexts(),
+        'max_age'=> $cache_metadata->getCacheMaxAge(),
+        'tags' => $cache_metadata->getCacheTags(),
+      ]);
+    }
+    $view->save(TRUE);
+  }
+
+  return t('Updated cacheability metadata of all the views.');
+
+}
+
+/**
  * @} End of "addtogroup updates-8.0.0-beta".
  */
