 core/includes/common.inc                           |    8 +-
 core/lib/Drupal/Core/Cache/CacheableHelper.php     |   89 +++++++++++++
 core/modules/block/block.module                    |   75 ++---------
 core/modules/block/lib/Drupal/block/BlockBase.php  |   66 +++++++++-
 .../lib/Drupal/block/BlockPluginInterface.php      |    3 +-
 .../block/lib/Drupal/block/BlockViewBuilder.php    |  135 ++++++++++++++------
 .../block/lib/Drupal/block/Entity/Block.php        |   28 ++++
 .../Drupal/block/Plugin/views/display/Block.php    |   46 -------
 .../lib/Drupal/block/Tests/BlockCacheTest.php      |   12 +-
 .../lib/Drupal/block/Tests/BlockInterfaceTest.php  |   14 +-
 .../Drupal/block/Tests/BlockRenderOrderTest.php    |    7 +-
 .../Drupal/block/Tests/BlockStorageUnitTest.php    |    4 +-
 .../block/lib/Drupal/block/Tests/BlockTest.php     |  122 ++++++++++++++----
 .../Drupal/block/Tests/Views/DisplayBlockTest.php  |   19 +--
 .../tests/Drupal/block/Tests/BlockBaseTest.php     |    5 -
 .../block_test/config/block.block.test_block.yml   |    1 -
 .../block_test/Plugin/Block/TestCacheBlock.php     |   12 +-
 .../block_test/Plugin/Block/TestXSSTitleBlock.php  |   12 --
 .../book/Plugin/Block/BookNavigationBlock.php      |    9 +-
 core/modules/forum/forum.module                    |   17 ---
 .../forum/Plugin/Block/ActiveTopicsBlock.php       |    8 +-
 .../Drupal/forum/Plugin/Block/ForumBlockBase.php   |   34 ++++-
 .../Drupal/forum/Plugin/Block/NewTopicsBlock.php   |    9 +-
 .../language/Plugin/Derivative/LanguageBlock.php   |    1 -
 .../menu/lib/Drupal/menu/Tests/MenuTest.php        |    9 +-
 .../lib/Drupal/simpletest/WebTestBase.php          |    4 +
 .../Drupal/system/Plugin/Block/SystemHelpBlock.php |   20 +++
 .../Drupal/system/Plugin/Block/SystemMainBlock.php |   20 +++
 .../Drupal/system/Plugin/Block/SystemMenuBlock.php |    8 +-
 .../system/Plugin/Block/SystemPoweredByBlock.php   |   14 ++
 .../system/Plugin/Derivative/SystemMenuBlock.php   |    1 -
 .../Tests/Cache/PageCacheTagsIntegrationTest.php   |   30 +++++
 .../lib/Drupal/views/Plugin/Block/ViewsBlock.php   |   24 +++-
 .../Drupal/views/Plugin/Derivative/ViewsBlock.php  |    1 -
 .../Plugin/Derivative/ViewsExposedFilterBlock.php  |    1 -
 .../Plugin/views/display/DisplayPluginBase.php     |    1 -
 .../views/Tests/Plugin/Block/ViewsBlockTest.php    |    3 -
 .../minimal/config/block.block.stark_admin.yml     |    1 -
 .../minimal/config/block.block.stark_login.yml     |    1 -
 .../minimal/config/block.block.stark_tools.yml     |    1 -
 .../config/block.block.bartik_breadcrumbs.yml      |    1 -
 .../standard/config/block.block.bartik_content.yml |    1 -
 .../standard/config/block.block.bartik_footer.yml  |    1 -
 .../standard/config/block.block.bartik_help.yml    |    1 -
 .../standard/config/block.block.bartik_login.yml   |    1 -
 .../standard/config/block.block.bartik_powered.yml |    1 -
 .../standard/config/block.block.bartik_search.yml  |    1 -
 .../standard/config/block.block.bartik_tools.yml   |    1 -
 .../config/block.block.seven_breadcrumbs.yml       |    1 -
 .../standard/config/block.block.seven_content.yml  |    1 -
 .../standard/config/block.block.seven_help.yml     |    1 -
 .../standard/config/block.block.seven_login.yml    |    1 -
 52 files changed, 590 insertions(+), 297 deletions(-)

diff --git a/core/includes/common.inc b/core/includes/common.inc
index ab11ddf..a2dd9ae 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\Url;
 use Drupal\Component\Utility\Xss;
 use Drupal\Core\Cache\Cache;
+use Drupal\Core\Cache\CacheableHelper;
 use Drupal\Core\Language\Language;
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\HttpFoundation\Request;
@@ -4622,9 +4623,14 @@ function drupal_render_cid_create($elements) {
     return $elements['#cache']['cid'];
   }
   elseif (isset($elements['#cache']['keys'])) {
+    // Add cache context keys when constants are used in the 'keys' parameter.
+    $cacheable_helper = new CacheableHelper;
+    $keys = $cacheable_helper->addCacheContextsToKeys($elements['#cache']['keys']);
+
     $granularity = isset($elements['#cache']['granularity']) ? $elements['#cache']['granularity'] : NULL;
     // Merge in additional cache ID parts based provided by drupal_render_cid_parts().
-    $cid_parts = array_merge($elements['#cache']['keys'], drupal_render_cid_parts($granularity));
+    $cid_parts = array_merge($keys, drupal_render_cid_parts($granularity));
+
     return implode(':', $cid_parts);
   }
   return FALSE;
diff --git a/core/lib/Drupal/Core/Cache/CacheableHelper.php b/core/lib/Drupal/Core/Cache/CacheableHelper.php
new file mode 100644
index 0000000..be1f402
--- /dev/null
+++ b/core/lib/Drupal/Core/Cache/CacheableHelper.php
@@ -0,0 +1,89 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Cache\CacheableHelper.
+ */
+
+namespace Drupal\Core\Cache;
+
+/**
+ * A helper class that contains methods that could be useful to any object using
+ * the Drupal Cache API.
+ *
+ * @todo Consider converting to a trait once traits are available.
+ */
+class CacheableHelper {
+
+  /**
+   * Generates a hash from a query object, to be used as part of the cache key
+   *
+   * @param $query
+   *   A select query object.
+   *
+   * @return string
+   *   A hash of the query arguments.
+   */
+  function keyFromQuery($query) {
+    $query->preExecute();
+    $keys = array((string) $query, $query->getArguments());
+    return hash('sha256', serialize($keys));
+  }
+
+  /**
+   * Converts cache contexts to string representations of the context.
+   *
+   * @param $keys
+   *   An array of cache keys that may or may not contain cache contexts.
+   * @return array
+   *   A copy of the input, with cache contexts converted.
+   */
+  function addCacheContextsToKeys($keys) {
+    $keys_with_contexts = array();
+    foreach ($keys as $key) {
+      $keys_with_contexts[] = $this->getContext($key) ?: $key;
+    }
+    return $keys_with_contexts;
+  }
+
+  /**
+   * Provides the string representaton of a cache context.
+   *
+   * @todo Document this properly once the input arguments are decided on,
+   * assuming the reuse of existing cache constants is temporary.
+   *
+   * @return string
+   *   The string representaton of a cache context.
+   */
+  protected function getContext($context) {
+    switch ($context) {
+    case DRUPAL_CACHE_PER_PAGE:
+      // @todo: Make this use the request properly.
+      return $this->currentPath();
+    case DRUPAL_CACHE_PER_USER:
+      return "u." . $this->currentUser()->id();
+    case DRUPAL_CACHE_PER_ROLE:
+      return 'r.' . implode(',', $this->currentUser()->getRoles());
+    default:
+      return FALSE;
+    }
+  }
+
+  /**
+   * @return \Drupal\Core\Session\AccountInterface
+   *   The current user.
+   */
+  protected function currentUser() {
+    return \Drupal::currentUser();
+  }
+
+  /**
+   * @return string
+   *   The current path.
+   */
+  protected function currentPath() {
+    global $base_root;
+    return $base_root . request_uri();
+  }
+
+}
diff --git a/core/modules/block/block.module b/core/modules/block/block.module
index e97852c..3018f38 100644
--- a/core/modules/block/block.module
+++ b/core/modules/block/block.module
@@ -169,53 +169,13 @@ function block_page_build(&$page) {
 function block_get_blocks_by_region($region) {
   $build = array();
   if ($list = block_list($region)) {
-    $build = _block_get_renderable_region($list);
-  }
-  return $build;
-}
-
-/**
- * Gets an array of blocks suitable for drupal_render().
- *
- * @param $list
- *   A list of blocks such as that returned by block_list().
- *
- * @return
- *   A renderable array.
- */
-function _block_get_renderable_region($list = array()) {
-  $build = array();
-  // Block caching is not compatible with node_access modules. We also
-  // preserve the submission of forms in blocks, by fetching from cache
-  // only if the request method is 'GET' (or 'HEAD'). User 1 being out of
-  // the regular 'roles define permissions' schema, it brings too many
-  // chances of having unwanted output get in the cache and later be served
-  // to other users. We therefore exclude user 1 from block caching.
-  $not_cacheable = \Drupal::currentUser()->id() == 1 ||
-    count(\Drupal::moduleHandler()->getImplementations('node_grants')) ||
-    !\Drupal::request()->isMethodSafe();
-
-  foreach ($list as $key => $block) {
-    $settings = $block->get('settings');
-    if ($not_cacheable || in_array($settings['cache'], array(DRUPAL_NO_CACHE, DRUPAL_CACHE_CUSTOM))) {
-      // Non-cached blocks get built immediately.
+    foreach ($list as $key => $block) {
       if ($block->access()) {
         $build[$key] = entity_view($block, 'block');
       }
     }
-    else {
-      $build[$key] = array(
-        '#block' => $block,
-        '#weight' => $block->get('weight'),
-        '#pre_render' => array('_block_get_renderable_block'),
-        '#cache' => array(
-          'keys' => array($key, $settings['module']),
-          'granularity' => $settings['cache'],
-          'bin' => 'block',
-          'tags' => array('content' => TRUE),
-        ),
-      );
-    }
+    // block_list() already returned the blocks in sorted order.
+    $build['#sorted'] = TRUE;
   }
   return $build;
 }
@@ -342,9 +302,7 @@ function block_list($region) {
     $blocks[$region] = array();
   }
 
-  uasort($blocks[$region], function($first, $second) {
-    return $first->weight === $second->weight ? 0 : ($first->weight < $second->weight ? -1 : 1);
-  });
+  uasort($blocks[$region], 'Drupal\block\Entity\Block::sort');
 
   return $blocks[$region];
 }
@@ -365,26 +323,6 @@ function block_load($entity_id) {
 }
 
 /**
- * Builds the content and label for a block.
- *
- * For cacheable blocks, this is called during #pre_render.
- *
- * @param $element
- *   A renderable array.
- *
- * @return
- *   A renderable array.
- */
-function _block_get_renderable_block($element) {
-  $block = $element['#block'];
-  // Don't bother to build blocks that aren't accessible.
-  if ($element['#access'] = $block->access()) {
-    $element += entity_view($block, 'block');
-  }
-  return $element;
-}
-
-/**
  * Implements hook_rebuild().
  */
 function block_rebuild() {
@@ -456,6 +394,11 @@ function template_preprocess_block(&$variables) {
   $variables['derivative_plugin_id'] = $variables['elements']['#derivative_plugin_id'];
   $variables['label'] = !empty($variables['configuration']['label_display']) ? $variables['configuration']['label'] : '';
   $variables['content'] = $variables['elements']['content'];
+  // A block's label is configuration: it is static. Allow dynamic labels to be
+  // set in the render array.
+  if (isset($variables['elements']['content']['#title']) && !empty($variables['configuration']['label_display'])) {
+    $variables['label'] = $variables['elements']['content']['#title'];
+  }
 
   $variables['attributes']['class'][] = 'block';
   $variables['attributes']['class'][] = drupal_html_class('block-' . $variables['configuration']['module']);
diff --git a/core/modules/block/lib/Drupal/block/BlockBase.php b/core/modules/block/lib/Drupal/block/BlockBase.php
index d278663..ede453f 100644
--- a/core/modules/block/lib/Drupal/block/BlockBase.php
+++ b/core/modules/block/lib/Drupal/block/BlockBase.php
@@ -11,6 +11,8 @@
 use Drupal\block\BlockInterface;
 use Drupal\Component\Utility\Unicode;
 use Drupal\Core\Language\Language;
+use Drupal\Core\Cache\Cache;
+use Drupal\Core\Cache\CacheableInterface;
 use Drupal\Core\Session\AccountInterface;
 
 /**
@@ -32,7 +34,9 @@ public function __construct(array $configuration, $plugin_id, array $plugin_defi
       'label' => '',
       'module' => $plugin_definition['module'],
       'label_display' => BlockInterface::BLOCK_LABEL_VISIBLE,
-      'cache' => DRUPAL_NO_CACHE,
+      'cache' => array(
+        'max_age' => 0,
+      ),
     );
   }
 
@@ -108,11 +112,20 @@ public function buildConfigurationForm(array $form, array &$form_state) {
       '#default_value' => ($this->configuration['label_display'] === BlockInterface::BLOCK_LABEL_VISIBLE),
       '#return_value' => BlockInterface::BLOCK_LABEL_VISIBLE,
     );
-    $form['cache'] = array(
-      '#type' => 'value',
-      '#value' => $this->configuration['cache'],
+    $ages = array(0, 60, 300, 1800, 3600, 21600, 86400, 604800, 2592000, 31536000, 315360000);
+    $form['cache']['max_age'] = array(
+      '#type' => 'select',
+      '#title' => t('Cache: Max age'),
+      '#description' => t('Choose how long this block may be cached. The default of 0 seconds means it will never be cached.'),
+      '#default_value' => $this->configuration['cache']['max_age'],
+      '#options' => array_map(array(\Drupal::service('date'), 'formatInterval'), array_combine($ages, $ages)),
     );
-
+    // Don't allow the user to configure the max age for this block if the block
+    // plugin declares itself not cacheable or if it declares itself permanently
+    // cacheable.
+    if (!$this->isCacheable() || $this->getCacheMaxAge() === Cache::PERMANENT) {
+      $form['cache']['#access'] = FALSE;
+    }
     // Add plugin-specific settings for this block type.
     $form += $this->blockForm($form, $form_state);
     return $form;
@@ -156,6 +169,7 @@ public function submitConfigurationForm(array &$form, array &$form_state) {
       $this->configuration['label'] = $form_state['values']['label'];
       $this->configuration['label_display'] = $form_state['values']['label_display'];
       $this->configuration['module'] = $form_state['values']['module'];
+      $this->configuration['cache'] = $form_state['values']['cache'];
       $this->blockSubmit($form, $form_state);
     }
   }
@@ -189,4 +203,46 @@ public function getMachineNameSuggestion() {
     return $transliterated;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheKeys() {
+    return array();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheTags() {
+    // If a block plugin's output changes, then it must be able to invalidate a
+    // cache tag that affects all instances of this block: across themes and
+    // across regions.
+    $block_plugin_cache_tag = str_replace(':', '__', $this->getPluginID());
+    return array('block_plugin' => array($block_plugin_cache_tag));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheBin() {
+    return 'block';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheMaxAge() {
+    return (int)$this->configuration['cache']['max_age'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isCacheable() {
+    // Similar to the page cache, a block is cacheable if it has a max age.
+    // Blocks that should never be cached can override this method to simply
+    // return FALSE.
+    return (bool)$this->configuration['cache']['max_age'] > 0;
+  }
+
 }
diff --git a/core/modules/block/lib/Drupal/block/BlockPluginInterface.php b/core/modules/block/lib/Drupal/block/BlockPluginInterface.php
index 047efd9..4f6bdc2 100644
--- a/core/modules/block/lib/Drupal/block/BlockPluginInterface.php
+++ b/core/modules/block/lib/Drupal/block/BlockPluginInterface.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\block;
 
+use Drupal\Core\Cache\CacheableInterface;
 use Drupal\Component\Plugin\PluginInspectionInterface;
 use Drupal\Component\Plugin\ConfigurablePluginInterface;
 use Drupal\Core\Plugin\PluginFormInterface;
@@ -20,7 +21,7 @@
  *   brif references to the important components that are not coupled to the
  *   interface.
  */
-interface BlockPluginInterface extends ConfigurablePluginInterface, PluginFormInterface, PluginInspectionInterface {
+interface BlockPluginInterface extends ConfigurablePluginInterface, PluginFormInterface, PluginInspectionInterface, CacheableInterface {
 
   /**
    * Indicates whether the block should be shown.
diff --git a/core/modules/block/lib/Drupal/block/BlockViewBuilder.php b/core/modules/block/lib/Drupal/block/BlockViewBuilder.php
index a076dc9..d6e5056 100644
--- a/core/modules/block/lib/Drupal/block/BlockViewBuilder.php
+++ b/core/modules/block/lib/Drupal/block/BlockViewBuilder.php
@@ -7,7 +7,9 @@
 
 namespace Drupal\block;
 
+use Drupal\Component\Utility\NestedArray;
 use Drupal\Component\Utility\String;
+use Drupal\Core\Cache\Cache;
 use Drupal\Core\Entity\EntityViewBuilder;
 use Drupal\Core\Entity\EntityViewBuilderInterface;
 use Drupal\Core\Entity\EntityInterface;
@@ -43,52 +45,54 @@ public function viewMultiple(array $entities = array(), $view_mode = 'full', $la
       $plugin_id = $plugin->getPluginId();
       $base_id = $plugin->getBasePluginId();
       $derivative_id = $plugin->getDerivativeId();
+      $configuration = $plugin->getConfiguration();
 
-      if ($content = $plugin->build()) {
-        $configuration = $plugin->getConfiguration();
-
-        // Create the render array for the block as a whole.
-        // @see template_preprocess_block().
-        $build[$key] = array(
-          '#theme' => 'block',
-          '#attributes' => array(),
-          '#contextual_links' => array(
-            'block' => array(
-              'route_parameters' => array('block' => $entity_id),
-            ),
+      // Create the render array for the block as a whole.
+      // @see template_preprocess_block().
+      $build[$entity_id] = array(
+        '#theme' => 'block',
+        '#attributes' => array(),
+        // All blocks get a "Configure block" contextual link.
+        '#contextual_links' => array(
+          'block' => array(
+            'route_parameters' => array('block' => $entity->id()),
           ),
-          '#configuration' => $configuration,
-          '#plugin_id' => $plugin_id,
-          '#base_plugin_id' => $base_id,
-          '#derivative_plugin_id' => $derivative_id,
+        ),
+        '#weight' => $entity->get('weight'),
+        '#configuration' => $configuration,
+        '#plugin_id' => $plugin_id,
+        '#base_plugin_id' => $base_id,
+        '#derivative_plugin_id' => $derivative_id,
+        // @todo Remove after fixing http://drupal.org/node/1989568.
+        '#block' => $entity,
+      );
+      $build[$entity_id]['#configuration']['label'] = check_plain($configuration['label']);
+
+      // Set cache tags; these always need to be set, whether the block is
+      // cacheable or not, so that the page cache is correctly informed.
+      $default_cache_tags = array(
+        'content' => TRUE,
+        'block_view' => TRUE,
+        'block' => array($entity->id()),
+      );
+      $build[$entity_id]['#cache']['tags'] = NestedArray::mergeDeep($default_cache_tags, $plugin->getCacheTags());
+
+
+      if ($plugin->isCacheable()) {
+        $build[$entity_id]['#pre_render'][] = array($this, 'buildBlock');
+        // Generic cache keys, with the block plugin's custom keys appended
+        // (usually cache context keys like DRUPAL_CACHE_PER_ROLE).
+        $default_cache_keys = array('entity_view', 'block', $entity->id(), $entity->langcode);
+        $build[$entity_id]['#cache'] += array(
+          'keys' => array_merge($default_cache_keys, $plugin->getCacheKeys()),
+          'bin' => $plugin->getCacheBin(),
+          'expire' => REQUEST_TIME + $plugin->getCacheMaxAge(),
         );
-        $build[$key]['#configuration']['label'] = String::checkPlain($configuration['label']);
-
-        // Place the $content returned by the block plugin into a 'content'
-        // child element, as a way to allow the plugin to have complete control
-        // of its properties and rendering (e.g., its own #theme) without
-        // conflicting with the properties used above, or alternate ones used
-        // by alternate block rendering approaches in contrib (e.g., Panels).
-        // However, the use of a child element is an implementation detail of
-        // this particular block rendering approach. Semantically, the content
-        // returned by the plugin "is the" block, and in particular,
-        // #attributes and #contextual_links is information about the *entire*
-        // block. Therefore, we must move these properties from $content and
-        // merge them into the top-level element.
-        foreach (array('#attributes', '#contextual_links') as $property) {
-          if (isset($content[$property])) {
-            $build[$key][$property] += $content[$property];
-            unset($content[$property]);
-          }
-        }
-        $build[$key]['content'] = $content;
       }
       else {
-        $build[$key] = array();
+        $build[$entity_id] = $this->buildBlock($build[$entity_id]);
       }
 
-      $this->moduleHandler()->alter(array('block_view', "block_view_$base_id"), $build[$key], $plugin);
-
       // @todo Remove after fixing http://drupal.org/node/1989568.
       $build[$key]['#block'] = $entity;
     }
@@ -96,8 +100,59 @@ public function viewMultiple(array $entities = array(), $view_mode = 'full', $la
   }
 
   /**
+   * #pre_render callback for building a block.
+   *
+   * Renders the content using the provided block plugin, and then:
+   * - if there is no content, aborts rendering, and makes sure the block won't
+   *   be rendered.
+   * - if there is content, moves the contextual links from the block content to
+   *   the block itself, and invokes the alter hooks.
+   */
+  public function buildBlock($build) {
+    $plugin = $build['#block']->getPlugin();
+    $content = $plugin->build();
+
+    if (!empty($content)) {
+      // Place the $content returned by the block plugin into a 'content' child
+      // element, as a way to allow the plugin to have complete control of its
+      // properties and rendering (e.g., its own #theme) without conflicting
+      // with the properties used above, or alternate ones used by alternate
+      // block rendering approaches in contrib (e.g., Panels). However, the use
+      // of a child element is an implementation detail of this particular block
+      // rendering approach. Semantically, the content returned by the plugin
+      // "is the" block, and in particular, #attributes and #contextual_links is
+      // information about the *entire* block. Therefore, we must move these
+      // properties from $content and merge them into the top-level element.
+      foreach (array('#attributes', '#contextual_links') as $property) {
+        if (isset($content[$property])) {
+          $build[$property] += $content[$property];
+          unset($content[$property]);
+        }
+      }
+      $build['content'] = $content;
+
+      $base_id = $plugin->getBasePluginId();
+      $this->moduleHandler()->alter(array('block_view', "block_view_$base_id"), $build, $plugin);
+
+      return $build;
+    }
+    else {
+      // Abort rendering.
+      return array('#access' => FALSE, '#printed' => TRUE);
+    }
+    return $build;
+   }
+
+  /**
    * {@inheritdoc}
    */
-  public function resetCache(array $ids = NULL) { }
+  public function resetCache(array $entities = NULL) {
+    if (isset($entities)) {
+      Cache::invalidateTags(array('block' => array_keys($entities)));
+    }
+    else {
+      Cache::invalidateTags(array('block_view' => TRUE));
+    }
+  }
 
 }
diff --git a/core/modules/block/lib/Drupal/block/Entity/Block.php b/core/modules/block/lib/Drupal/block/Entity/Block.php
index c0d4de9..79a772e 100644
--- a/core/modules/block/lib/Drupal/block/Entity/Block.php
+++ b/core/modules/block/lib/Drupal/block/Entity/Block.php
@@ -7,7 +7,9 @@
 
 namespace Drupal\block\Entity;
 
+use Drupal\Core\Cache\Cache;
 use Drupal\Core\Config\Entity\ConfigEntityBase;
+use Drupal\Core\Entity\EntityStorageControllerInterface;
 use Drupal\block\BlockPluginBag;
 use Drupal\block\BlockInterface;
 use Drupal\Core\Config\Entity\EntityWithPluginBagInterface;
@@ -153,6 +155,32 @@ public function getExportProperties() {
   }
 
   /**
+   * {@inheritdoc}
+   */
+  public function postSave(EntityStorageControllerInterface $storage_controller, $update = TRUE) {
+    parent::postSave($storage_controller, $update);
+
+    if ($update) {
+      Cache::invalidateTags(array('block' => $this->id()));
+    }
+    // When placing a new block, invalidate all cache entries for this theme,
+    // since any page that uses this theme might be affected.
+    else {
+      // @todo Replace with theme cache tag: https://drupal.org/node/2185617
+      Cache::invalidateTags(array('content' => TRUE));
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function postDelete(EntityStorageControllerInterface $storage_controller, array $entities) {
+    parent::postDelete($storage_controller, $entities);
+
+    Cache::invalidateTags(array('block' => array_keys($entities)));
+  }
+
+  /**
    * Sorts active blocks by weight; sorts inactive blocks by name.
    */
   public static function sort($a, $b) {
diff --git a/core/modules/block/lib/Drupal/block/Plugin/views/display/Block.php b/core/modules/block/lib/Drupal/block/Plugin/views/display/Block.php
index 657b635..94bea95 100644
--- a/core/modules/block/lib/Drupal/block/Plugin/views/display/Block.php
+++ b/core/modules/block/lib/Drupal/block/Plugin/views/display/Block.php
@@ -46,7 +46,6 @@ protected function defineOptions() {
 
     $options['block_description'] = array('default' => '', 'translatable' => TRUE);
     $options['block_category'] = array('default' => 'Lists (Views)', 'translatable' => TRUE);
-    $options['block_caching'] = array('default' => DRUPAL_NO_CACHE);
     $options['block_hide_empty'] = array('default' => FALSE);
 
     $options['allow'] = array(
@@ -131,13 +130,6 @@ public function optionsSummary(&$categories, &$options) {
       'value' => empty($filtered_allow) ? t('None') : t('Items per page'),
     );
 
-    $types = $this->blockCachingModes();
-    $options['block_caching'] = array(
-      'category' => 'other',
-      'title' => t('Block caching'),
-      'value' => $types[$this->getCacheType()],
-    );
-
     $options['block_hide_empty'] = array(
       'category' => 'other',
       'title' => t('Hide block if the view output is empty'),
@@ -146,33 +138,6 @@ public function optionsSummary(&$categories, &$options) {
   }
 
   /**
-   * Provide a list of core's block caching modes.
-   */
-  protected function blockCachingModes() {
-    return array(
-      DRUPAL_NO_CACHE => t('Do not cache'),
-      DRUPAL_CACHE_GLOBAL => t('Cache once for everything (global)'),
-      DRUPAL_CACHE_PER_PAGE => t('Per page'),
-      DRUPAL_CACHE_PER_ROLE => t('Per role'),
-      DRUPAL_CACHE_PER_ROLE | DRUPAL_CACHE_PER_PAGE => t('Per role per page'),
-      DRUPAL_CACHE_PER_USER => t('Per user'),
-      DRUPAL_CACHE_PER_USER | DRUPAL_CACHE_PER_PAGE => t('Per user per page'),
-    );
-  }
-
-  /**
-   * Provide a single method to figure caching type, keeping a sensible default
-   * for when it's unset.
-   */
-  public function getCacheType() {
-    $cache_type = $this->getOption('block_caching');
-    if (empty($cache_type)) {
-      $cache_type = DRUPAL_NO_CACHE;
-    }
-    return $cache_type;
-  }
-
-  /**
    * Provide the default form for setting options.
    */
   public function buildOptionsForm(&$form, &$form_state) {
@@ -196,16 +161,6 @@ public function buildOptionsForm(&$form, &$form_state) {
           '#default_value' => $this->getOption('block_category'),
         );
         break;
-      case 'block_caching':
-        $form['#title'] .= t('Block caching type');
-
-        $form['block_caching'] = array(
-          '#type' => 'radios',
-          '#description' => t("This sets the default status for Drupal's built-in block caching method; this requires that caching be turned on in block administration, and be careful because you have little control over when this cache is flushed."),
-          '#options' => $this->blockCachingModes(),
-          '#default_value' => $this->getCacheType(),
-        );
-        break;
       case 'block_hide_empty':
         $form['#title'] .= t('Block empty settings');
 
@@ -251,7 +206,6 @@ public function submitOptionsForm(&$form, &$form_state) {
     switch ($form_state['section']) {
       case 'block_description':
       case 'block_category':
-      case 'block_caching':
       case 'allow':
       case 'block_hide_empty':
         $this->setOption($form_state['section'], $form_state['values'][$form_state['section']]);
diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockCacheTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockCacheTest.php
index 7414efd..8679e0b 100644
--- a/core/modules/block/lib/Drupal/block/Tests/BlockCacheTest.php
+++ b/core/modules/block/lib/Drupal/block/Tests/BlockCacheTest.php
@@ -128,14 +128,16 @@ function testCacheGlobal() {
   }
 
   /**
-   * Test DRUPAL_NO_CACHE.
+   * Test non-cacheable block.
    */
   function testNoCache() {
-    $this->setCacheMode(DRUPAL_NO_CACHE);
+    $this->block->getPlugin()->setConfigurationValue('cache', array('max_age' => 0));
+    $this->block->save();
+
     $current_content = $this->randomName();
     \Drupal::state()->set('block_test.content', $current_content);
 
-    // If DRUPAL_NO_CACHE has no effect, the next request would be cached.
+    // If max_age = 0 has no effect, the next request would be cached.
     $this->drupalGet('');
     $this->assertText($current_content, 'Block content displays.');
 
@@ -199,7 +201,9 @@ function testCachePerPage() {
    * Private helper method to set the test block's cache mode.
    */
   private function setCacheMode($cache_mode) {
-    $this->block->getPlugin()->setConfigurationValue('cache', $cache_mode);
+    $block = $this->block->getPlugin();
+    $block->setConfigurationValue('cache', array('max_age' => 600));
+    $block->setConfigurationValue('test_cache_contexts', array($cache_mode));
     $this->block->save();
   }
 
diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockInterfaceTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockInterfaceTest.php
index a694b4e..34ee065 100644
--- a/core/modules/block/lib/Drupal/block/Tests/BlockInterfaceTest.php
+++ b/core/modules/block/lib/Drupal/block/Tests/BlockInterfaceTest.php
@@ -48,7 +48,9 @@ public function testBlockInterface() {
       'display_message' => 'no message set',
       'module' => 'block_test',
       'label_display' => BlockInterface::BLOCK_LABEL_VISIBLE,
-      'cache' => DRUPAL_NO_CACHE,
+      'cache' => array(
+        'max_age' => 0,
+      ),
     );
     // Initial configuration of the block at construction time.
     $display_block = $manager->createInstance('test_block_instantiation', $configuration);
@@ -60,6 +62,7 @@ public function testBlockInterface() {
     $this->assertIdentical($display_block->getConfiguration(), $expected_configuration, 'The block configuration was updated correctly.');
     $definition = $display_block->getPluginDefinition();
 
+    $ages = array(0, 60, 300, 1800, 3600, 21600, 86400, 604800, 2592000, 31536000, 315360000);
     $expected_form = array(
       'module' => array(
         '#type' => 'value',
@@ -84,8 +87,13 @@ public function testBlockInterface() {
         '#return_value' => 'visible',
       ),
       'cache' => array(
-        '#type' => 'value',
-        '#value' => DRUPAL_NO_CACHE,
+        'max_age' => array(
+          '#type' => 'select',
+          '#title' => t('Cache: Max age'),
+          '#description' => t('Choose how long this block may be cached. The default of 0 seconds means it will never be cached.'),
+          '#default_value' => 0,
+          '#options' => array_map(array(\Drupal::service('date'), 'formatInterval'), array_combine($ages, $ages)),
+        ),
       ),
       'display_message' => array(
         '#type' => 'textfield',
diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockRenderOrderTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockRenderOrderTest.php
index 0521aa9..1a7ea82 100644
--- a/core/modules/block/lib/Drupal/block/Tests/BlockRenderOrderTest.php
+++ b/core/modules/block/lib/Drupal/block/Tests/BlockRenderOrderTest.php
@@ -48,21 +48,24 @@ function testBlockRenderOrder() {
       'stark_powered' => array(
         'weight' => '-3',
         'id' => 'stark_powered',
+        'label' => 'Test block A',
       ),
       'stark_by' => array(
         'weight' => '3',
         'id' => 'stark_by',
+        'label' => 'Test block C',
       ),
       'stark_drupal' => array(
         'weight' => '3',
         'id' => 'stark_drupal',
+        'label' => 'Test block B',
       ),
     );
 
     // Place the test blocks.
     foreach ($test_blocks as $test_block) {
       $this->drupalPlaceBlock('system_powered_by_block', array(
-        'label' => 'Test Block',
+        'label' => $test_block['label'],
         'region' => $region,
         'weight' => $test_block['weight'],
         'id' => $test_block['id'],
@@ -81,6 +84,6 @@ function testBlockRenderOrder() {
       }
     }
     $this->assertTrue($position['stark_powered'] < $position['stark_by'], 'Blocks with different weight are rendered in the correct order.');
-    $this->assertTrue($position['stark_drupal'] < $position['stark_by'], 'Blocks with identical weight are rendered in reverse alphabetical order.');
+    $this->assertTrue($position['stark_drupal'] < $position['stark_by'], 'Blocks with identical weight are rendered in alphabetical order.');
   }
 }
diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockStorageUnitTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockStorageUnitTest.php
index d9cb5b1..9c9ff2a 100644
--- a/core/modules/block/lib/Drupal/block/Tests/BlockStorageUnitTest.php
+++ b/core/modules/block/lib/Drupal/block/Tests/BlockStorageUnitTest.php
@@ -102,7 +102,9 @@ protected function createTests() {
         'label' => '',
         'module' => 'block_test',
         'label_display' => BlockInterface::BLOCK_LABEL_VISIBLE,
-        'cache' => DRUPAL_NO_CACHE,
+        'cache' => array(
+          'max_age' => 0,
+        ),
       ),
       'visibility' => NULL,
     );
diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockTest.php
index e7b99e1..cc25986 100644
--- a/core/modules/block/lib/Drupal/block/Tests/BlockTest.php
+++ b/core/modules/block/lib/Drupal/block/Tests/BlockTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\block\Tests;
 
+use Drupal\Core\Cache\Cache;
 use Drupal\simpletest\WebTestBase;
 
 /**
@@ -249,35 +250,106 @@ function moveBlockToRegion(array $block, $region) {
   }
 
   /**
-   * Test _block_rehash().
+   * Test that cache tags are properly set and bubbled up to the page cache.
+   *
+   * Verify that invalidation of these cache tags works:
+   * - "block:<block ID>"
+   * - "block_plugin:<block plugin ID>"
    */
-  function testBlockRehash() {
-    \Drupal::moduleHandler()->install(array('block_test'));
-    $this->assertTrue(\Drupal::moduleHandler()->moduleExists('block_test'), 'Test block module enabled.');
-
-    // Clear the block cache to load the block_test module's block definitions.
-    $this->container->get('plugin.manager.block')->clearCachedDefinitions();
-
-    // Add a test block.
-    $block = array();
-    $block['id'] = 'test_cache';
-    $block['theme'] = \Drupal::config('system.theme')->get('default');
-    $block['region'] = 'header';
-    $block = $this->drupalPlaceBlock('test_cache', array('region' => 'header'));
+  public function testBlockCacheTags() {
+    // The page cache only works for anonymous users.
+    $this->drupalLogout();
 
-    // Our test block's caching should default to DRUPAL_CACHE_PER_ROLE.
-    $settings = $block->get('settings');
-    $this->assertEqual($settings['cache'], DRUPAL_CACHE_PER_ROLE, 'Test block cache mode defaults to DRUPAL_CACHE_PER_ROLE.');
+    // Enable page caching.
+    $config = \Drupal::config('system.performance');
+    $config->set('cache.page.use_internal', 1);
+    $config->set('cache.page.max_age', 300);
+    $config->save();
+
+    // Place the "Powered by Drupal" block.
+    $block = $this->drupalPlaceBlock('system_powered_by_block', array('id' => 'powered', 'cache' => array('max_age' => 315360000)));
+
+    // Prime the page cache.
+    $this->drupalGet('<front>');
+    $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS');
+
+    // Verify a cache hit, but also the presence of the correct cache tags in
+    // both the page and block caches.
+    $this->drupalGet('<front>');
+    $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT');
+    $cid_parts = array(url('<front>', array('absolute' => TRUE)), 'html');
+    $cid = sha1(implode(':', $cid_parts));
+    $cache_entry = \Drupal::cache('page')->get($cid);
+    $expected_cache_tags = array(
+      'content:1',
+      'block_view:1',
+      'block:powered',
+      'block_plugin:system_powered_by_block',
+    );
+    $this->assertIdentical($cache_entry->tags, $expected_cache_tags);
+    $cache_entry = \Drupal::cache('block')->get('entity_view:block:powered:en:stark');
+    $this->assertIdentical($cache_entry->tags, $expected_cache_tags);
 
-    // Disable caching for this block.
-    $block->getPlugin()->setConfigurationValue('cache', DRUPAL_NO_CACHE);
+    // The "Powered by Drupal" block is modified; verify a cache miss.
+    $block->set('region', 'content');
     $block->save();
-    // Flushing all caches should call _block_rehash().
-    $this->resetAll();
-    // Verify that block is updated with the new caching mode.
-    $block = entity_load('block', $block->id());
-    $settings = $block->get('settings');
-    $this->assertEqual($settings['cache'], DRUPAL_NO_CACHE, "Test block's database entry updated to DRUPAL_NO_CACHE.");
+    $this->drupalGet('<front>');
+    $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS');
+
+    // Now we should have a cache hit again.
+    $this->drupalGet('<front>');
+    $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT');
+
+    // Place the "Powered by Drupal" block another time; verify a cache miss.
+    $block_2 = $this->drupalPlaceBlock('system_powered_by_block', array('id' => 'powered-2', 'cache' => array('max_age' => 315360000)));
+    $this->drupalGet('<front>');
+    $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS');
+
+    // Verify a cache hit, but also the presence of the correct cache tags.
+    $this->drupalGet('<front>');
+    $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT');
+    $cid_parts = array(url('<front>', array('absolute' => TRUE)), 'html');
+    $cid = sha1(implode(':', $cid_parts));
+    $cache_entry = \Drupal::cache('page')->get($cid);
+    $expected_cache_tags = array(
+      'content:1',
+      'block_view:1',
+      'block:powered-2',
+      'block:powered',
+      'block_plugin:system_powered_by_block',
+    );
+    $this->assertEqual($cache_entry->tags, $expected_cache_tags);
+    $expected_cache_tags = array(
+      'content:1',
+      'block_view:1',
+      'block:powered',
+      'block_plugin:system_powered_by_block',
+    );
+    $cache_entry = \Drupal::cache('block')->get('entity_view:block:powered:en:stark');
+    $this->assertIdentical($cache_entry->tags, $expected_cache_tags);
+    $expected_cache_tags = array(
+      'content:1',
+      'block_view:1',
+      'block:powered-2',
+      'block_plugin:system_powered_by_block',
+    );
+    $cache_entry = \Drupal::cache('block')->get('entity_view:block:powered-2:en:stark');
+    $this->assertIdentical($cache_entry->tags, $expected_cache_tags);
+
+    // The plugin providing the "Powered by Drupal" block is modified; verify a
+    // cache miss.
+    Cache::invalidateTags(array('block_plugin:system_powered_by_block'));
+    $this->drupalGet('<front>');
+    $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS');
+
+    // Now we should have a cache hit again.
+    $this->drupalGet('<front>');
+    $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT');
+
+    // Delete the "Powered by Drupal" blocks; verify a cache miss.
+    entity_delete_multiple('block', array('powered', 'powered-2'));
+    $this->drupalGet('<front>');
+    $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS');
   }
 
 }
diff --git a/core/modules/block/lib/Drupal/block/Tests/Views/DisplayBlockTest.php b/core/modules/block/lib/Drupal/block/Tests/Views/DisplayBlockTest.php
index 3c9745f..441e5e4 100644
--- a/core/modules/block/lib/Drupal/block/Tests/Views/DisplayBlockTest.php
+++ b/core/modules/block/lib/Drupal/block/Tests/Views/DisplayBlockTest.php
@@ -175,19 +175,6 @@ protected function testDeleteBlockDisplay() {
   }
 
   /**
-   * Tests views block plugin definitions.
-   */
-  public function testViewsBlockPlugins() {
-    // Ensures that the cache setting gets to the block settings.
-    $instance = $this->container->get('plugin.manager.block')->createInstance('views_block:test_view_block2-block_2');
-    $configuration = $instance->getConfiguration();
-    $this->assertEqual($configuration['cache'], DRUPAL_NO_CACHE);
-    $instance = $this->container->get('plugin.manager.block')->createInstance('views_block:test_view_block2-block_3');
-    $configuration = $instance->getConfiguration();
-    $this->assertEqual($configuration['cache'], DRUPAL_CACHE_PER_USER);
-  }
-
-  /**
    * Test the block form for a Views block.
    */
   public function testViewsBlockForm() {
@@ -281,19 +268,23 @@ public function testBlockRendering() {
   public function testBlockContextualLinks() {
     $this->drupalLogin($this->drupalCreateUser(array('administer views', 'access contextual links', 'administer blocks')));
     $block = $this->drupalPlaceBlock('views_block:test_view_block-block_1');
+    $cached_block = $this->drupalPlaceBlock('views_block:test_view_block-block_1', array('cache' => array('max_age' => 3600)));
     $this->drupalGet('test-page');
 
     $id = 'block:block=' . $block->id() . ':|views_ui_edit:view=test_view_block:location=block&name=test_view_block&display_id=block_1';
+    $cached_id = 'block:block=' . $cached_block->id() . ':|views_ui_edit:view=test_view_block:location=block&name=test_view_block&display_id=block_1';
     // @see \Drupal\contextual\Tests\ContextualDynamicContextTest:assertContextualLinkPlaceHolder()
     $this->assertRaw('<div' . new Attribute(array('data-contextual-id' => $id)) . '></div>', format_string('Contextual link placeholder with id @id exists.', array('@id' => $id)));
+    $this->assertRaw('<div' . new Attribute(array('data-contextual-id' => $cached_id)) . '></div>', format_string('Contextual link placeholder with id @id exists.', array('@id' => $cached_id)));
 
     // Get server-rendered contextual links.
     // @see \Drupal\contextual\Tests\ContextualDynamicContextTest:renderContextualLinks()
-    $post = array('ids[0]' => $id);
+    $post = array('ids[0]' => $id, 'ids[1]' => $cached_id);
     $response = $this->drupalPost('contextual/render', 'application/json', $post, array('query' => array('destination' => 'test-page')));
     $this->assertResponse(200);
     $json = drupal_json_decode($response);
     $this->assertIdentical($json[$id], '<ul class="contextual-links"><li class="block-configure"><a href="' . base_path() . 'admin/structure/block/manage/' . $block->id() . '">Configure block</a></li><li class="views-uiedit"><a href="' . base_path() . 'admin/structure/views/view/test_view_block/edit/block_1">Edit view</a></li></ul>');
+    $this->assertIdentical($json[$cached_id], '<ul class="contextual-links"><li class="block-configure"><a href="' . base_path() . 'admin/structure/block/manage/' . $cached_block->id() . '">Configure block</a></li><li class="views-uiedit"><a href="' . base_path() . 'admin/structure/views/view/test_view_block/edit/block_1">Edit view</a></li></ul>');
   }
 
 }
diff --git a/core/modules/block/tests/Drupal/block/Tests/BlockBaseTest.php b/core/modules/block/tests/Drupal/block/Tests/BlockBaseTest.php
index f0d04ec..8d96c33 100644
--- a/core/modules/block/tests/Drupal/block/Tests/BlockBaseTest.php
+++ b/core/modules/block/tests/Drupal/block/Tests/BlockBaseTest.php
@@ -12,11 +12,6 @@
 use Drupal\Core\Transliteration\PHPTransliteration;
 use Drupal\Tests\UnitTestCase;
 
-// @todo Remove once the constants are replaced with constants on classes.
-if (!defined('DRUPAL_NO_CACHE')) {
-  define('DRUPAL_NO_CACHE', -1);
-}
-
 /**
  * Tests the base block plugin.
  *
diff --git a/core/modules/block/tests/modules/block_test/config/block.block.test_block.yml b/core/modules/block/tests/modules/block_test/config/block.block.test_block.yml
index 9a8383c..9c00b0b 100644
--- a/core/modules/block/tests/modules/block_test/config/block.block.test_block.yml
+++ b/core/modules/block/tests/modules/block_test/config/block.block.test_block.yml
@@ -9,7 +9,6 @@ settings:
   label: 'Test HTML block'
   module: block_test
   label_display: 'hidden'
-  cache: 1
 visibility:
   path:
     visibility: 0
diff --git a/core/modules/block/tests/modules/block_test/lib/Drupal/block_test/Plugin/Block/TestCacheBlock.php b/core/modules/block/tests/modules/block_test/lib/Drupal/block_test/Plugin/Block/TestCacheBlock.php
index 2fa6122..ad8dab1 100644
--- a/core/modules/block/tests/modules/block_test/lib/Drupal/block_test/Plugin/Block/TestCacheBlock.php
+++ b/core/modules/block/tests/modules/block_test/lib/Drupal/block_test/Plugin/Block/TestCacheBlock.php
@@ -21,22 +21,18 @@ class TestCacheBlock extends BlockBase {
 
   /**
    * {@inheritdoc}
-   *
-   * Sets a different caching strategy for testing purposes.
    */
-  public function defaultConfiguration() {
+  public function build() {
     return array(
-      'cache' => DRUPAL_CACHE_PER_ROLE,
+      '#markup' => \Drupal::state()->get('block_test.content'),
     );
   }
 
   /**
    * {@inheritdoc}
    */
-  public function build() {
-    return array(
-      '#children' => \Drupal::state()->get('block_test.content'),
-    );
+  public function getCacheKeys() {
+    return $this->configuration['test_cache_contexts'];
   }
 
 }
diff --git a/core/modules/block/tests/modules/block_test/lib/Drupal/block_test/Plugin/Block/TestXSSTitleBlock.php b/core/modules/block/tests/modules/block_test/lib/Drupal/block_test/Plugin/Block/TestXSSTitleBlock.php
index 156abf9..3146b59 100644
--- a/core/modules/block/tests/modules/block_test/lib/Drupal/block_test/Plugin/Block/TestXSSTitleBlock.php
+++ b/core/modules/block/tests/modules/block_test/lib/Drupal/block_test/Plugin/Block/TestXSSTitleBlock.php
@@ -16,16 +16,4 @@
  * )
  */
 class TestXSSTitleBlock extends TestCacheBlock {
-
-  /**
-   * {@inheritdoc}
-   *
-   * Sets a different caching strategy for testing purposes.
-   */
-  public function defaultConfiguration() {
-    return array(
-      'cache' => DRUPAL_NO_CACHE,
-    );
-  }
-
 }
diff --git a/core/modules/book/lib/Drupal/book/Plugin/Block/BookNavigationBlock.php b/core/modules/book/lib/Drupal/book/Plugin/Block/BookNavigationBlock.php
index 4350e53..1454675 100644
--- a/core/modules/book/lib/Drupal/book/Plugin/Block/BookNavigationBlock.php
+++ b/core/modules/book/lib/Drupal/book/Plugin/Block/BookNavigationBlock.php
@@ -65,7 +65,6 @@ public static function create(ContainerInterface $container, array $configuratio
    */
   public function defaultConfiguration() {
     return array(
-      'cache' => DRUPAL_CACHE_PER_PAGE | DRUPAL_CACHE_PER_ROLE,
       'block_mode' => "all pages",
     );
   }
@@ -101,6 +100,7 @@ public function blockSubmit($form, &$form_state) {
    */
   public function build() {
     $current_bid = 0;
+
     if ($node = $this->request->get('node')) {
       $current_bid = empty($node->book['bid']) ? 0 : $node->book['bid'];
     }
@@ -156,4 +156,11 @@ public function build() {
     return array();
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheKeys() {
+    return array(DRUPAL_CACHE_PER_PAGE, DRUPAL_CACHE_PER_ROLE);
+  }
+
 }
diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module
index b1bb1ea..2fd36b5 100644
--- a/core/modules/forum/forum.module
+++ b/core/modules/forum/forum.module
@@ -538,23 +538,6 @@ function forum_form_node_form_alter(&$form, &$form_state, $form_id) {
 }
 
 /**
- * Render API callback: Lists nodes based on the element's #query property.
- *
- * This function can be used as a #pre_render callback.
- *
- * @see \Drupal\forum\Plugin\block\block\NewTopicsBlock::build()
- * @see \Drupal\forum\Plugin\block\block\ActiveTopicsBlock::build()
- */
-function forum_block_view_pre_render($elements) {
-  $result = $elements['#query']->execute();
-  if ($node_title_list = node_title_list($result)) {
-    $elements['forum_list'] = $node_title_list;
-    $elements['forum_more'] = array('#theme' => 'more_link', '#url' => 'forum', '#title' => t('Read the latest forum topics.'));
-  }
-  return $elements;
-}
-
-/**
  * Implements hook_preprocess_HOOK() for block templates.
  */
 function forum_preprocess_block(&$variables) {
diff --git a/core/modules/forum/lib/Drupal/forum/Plugin/Block/ActiveTopicsBlock.php b/core/modules/forum/lib/Drupal/forum/Plugin/Block/ActiveTopicsBlock.php
index d83f736..133529a 100644
--- a/core/modules/forum/lib/Drupal/forum/Plugin/Block/ActiveTopicsBlock.php
+++ b/core/modules/forum/lib/Drupal/forum/Plugin/Block/ActiveTopicsBlock.php
@@ -21,17 +21,13 @@ class ActiveTopicsBlock extends ForumBlockBase {
   /**
    * {@inheritdoc}
    */
-  public function build() {
-    $query = db_select('forum_index', 'f')
+  protected function buildForumQuery() {
+    return db_select('forum_index', 'f')
       ->fields('f')
       ->addTag('node_access')
       ->addMetaData('base_table', 'forum_index')
       ->orderBy('f.last_comment_timestamp', 'DESC')
       ->range(0, $this->configuration['block_count']);
-
-    return array(
-      drupal_render_cache_by_query($query, 'forum_block_view'),
-    );
   }
 
 }
diff --git a/core/modules/forum/lib/Drupal/forum/Plugin/Block/ForumBlockBase.php b/core/modules/forum/lib/Drupal/forum/Plugin/Block/ForumBlockBase.php
index f1c2f4e..d088b23 100644
--- a/core/modules/forum/lib/Drupal/forum/Plugin/Block/ForumBlockBase.php
+++ b/core/modules/forum/lib/Drupal/forum/Plugin/Block/ForumBlockBase.php
@@ -9,6 +9,7 @@
 
 use Drupal\block\BlockBase;
 use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Cache\CacheableHelper;
 
 /**
  * Provides a base class for Forum blocks.
@@ -18,9 +19,32 @@
   /**
    * {@inheritdoc}
    */
+  public function build() {
+    $result = $this->buildForumQuery()->execute();
+    if ($node_title_list = node_title_list($result)) {
+      $elements['forum_list'] = $node_title_list;
+      $elements['forum_more'] = array(
+        '#theme' => 'more_link',
+        '#url' => 'forum',
+        '#title' => t('Read the latest forum topics.')
+      );
+    }
+    return $elements;
+  }
+
+  /**
+   * Builds the select query to use for this forum block.
+   *
+   * @return \Drupal\Core\Database\Query\Select
+   *   A Select object.
+   */
+  abstract protected function buildForumQuery();
+
+  /**
+   * {@inheritdoc}
+   */
   public function defaultConfiguration() {
     return array(
-      'cache' => DRUPAL_CACHE_CUSTOM,
       'properties' => array(
         'administrative' => TRUE,
       ),
@@ -56,4 +80,12 @@ public function blockSubmit($form, &$form_state) {
     $this->configuration['block_count'] = $form_state['values']['block_count'];
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheKeys() {
+    $cacheable_helper = new CacheableHelper;
+    return array($cacheable_helper->cacheKeyFromQuery($this->buildForumQuery()));
+  }
+
 }
diff --git a/core/modules/forum/lib/Drupal/forum/Plugin/Block/NewTopicsBlock.php b/core/modules/forum/lib/Drupal/forum/Plugin/Block/NewTopicsBlock.php
index 8b75a83..635dab4 100644
--- a/core/modules/forum/lib/Drupal/forum/Plugin/Block/NewTopicsBlock.php
+++ b/core/modules/forum/lib/Drupal/forum/Plugin/Block/NewTopicsBlock.php
@@ -21,17 +21,12 @@ class NewTopicsBlock extends ForumBlockBase {
   /**
    * {@inheritdoc}
    */
-  public function build() {
-    $query = db_select('forum_index', 'f')
+  protected function buildForumQuery() {
+    return db_select('forum_index', 'f')
       ->fields('f')
       ->addTag('node_access')
       ->addMetaData('base_table', 'forum_index')
       ->orderBy('f.created', 'DESC')
       ->range(0, $this->configuration['block_count']);
-
-    return array(
-      drupal_render_cache_by_query($query, 'forum_block_view'),
-    );
   }
-
 }
diff --git a/core/modules/language/lib/Drupal/language/Plugin/Derivative/LanguageBlock.php b/core/modules/language/lib/Drupal/language/Plugin/Derivative/LanguageBlock.php
index acf276f..0de6dcf 100644
--- a/core/modules/language/lib/Drupal/language/Plugin/Derivative/LanguageBlock.php
+++ b/core/modules/language/lib/Drupal/language/Plugin/Derivative/LanguageBlock.php
@@ -27,7 +27,6 @@ public function getDerivativeDefinitions(array $base_plugin_definition) {
       foreach ($configurable_types as $type) {
         $this->derivatives[$type] = $base_plugin_definition;
         $this->derivatives[$type]['admin_label'] = t('Language switcher (!type)', array('!type' => $info[$type]['name']));
-        $this->derivatives[$type]['cache'] = DRUPAL_NO_CACHE;
       }
       // If there is just one configurable type then change the title of the
       // block.
diff --git a/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php b/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php
index d926528..34d515a 100644
--- a/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php
+++ b/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php
@@ -515,7 +515,14 @@ public function testMenuBlockPageCacheTags() {
     $cid_parts = array(url('test-page', array('absolute' => TRUE)), 'html');
     $cid = sha1(implode(':', $cid_parts));
     $cache_entry = \Drupal::cache('page')->get($cid);
-    $this->assertIdentical($cache_entry->tags, array('content:1', 'menu:llama'));
+    $expected_cache_tags = array(
+      'content:1',
+      'block_view:1',
+      'block:' . $block->id(),
+      'block_plugin:system_menu_block__llama',
+      'menu:llama',
+    );
+    $this->assertIdentical($cache_entry->tags, $expected_cache_tags);
 
     // The "Llama" menu is modified.
     $menu->label = 'Awesome llama';
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
index a442dd0..1404bfc 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
@@ -358,6 +358,7 @@ protected function drupalCreateContentType(array $values = array()) {
    *   - region: 'sidebar_first'.
    *   - theme: The default theme.
    *   - visibility: Empty array.
+   *   - cache: array('max_age' => 0).
    *
    * @return \Drupal\block\Entity\Block
    *   The block entity.
@@ -374,6 +375,9 @@ protected function drupalPlaceBlock($plugin_id, array $settings = array()) {
       'label' => $this->randomName(8),
       'visibility' => array(),
       'weight' => 0,
+      'cache' => array(
+        'max_age' => 0,
+      ),
     );
     foreach (array('region', 'id', 'theme', 'plugin', 'visibility', 'weight') as $key) {
       $values[$key] = $settings[$key];
diff --git a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemHelpBlock.php b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemHelpBlock.php
index f669e61..99cf5c3 100644
--- a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemHelpBlock.php
+++ b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemHelpBlock.php
@@ -117,4 +117,24 @@ public function build() {
     );
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function buildConfigurationForm(array $form, array &$form_state) {
+    $form = parent::buildConfigurationForm($form, $form_state);
+
+    // The help block is never cacheable, because it is path-specific.
+    $form['cache']['#access'] = FALSE;
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isCacheable() {
+    // The help block is never cacheable, because it is path-specific.
+    return FALSE;
+  }
+
 }
diff --git a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMainBlock.php b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMainBlock.php
index a64951a..4f22b64 100644
--- a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMainBlock.php
+++ b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMainBlock.php
@@ -28,4 +28,24 @@ public function build() {
     );
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function buildConfigurationForm(array $form, array &$form_state) {
+    $form = parent::buildConfigurationForm($form, $form_state);
+
+    // The main content block is never cacheable, because it may be dynamic.
+    $form['cache']['#access'] = FALSE;
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isCacheable() {
+    // The main content block is never cacheable, because it may be dynamic.
+    return FALSE;
+  }
+
 }
diff --git a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMenuBlock.php b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMenuBlock.php
index 8298193..f44e533 100644
--- a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMenuBlock.php
+++ b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMenuBlock.php
@@ -8,7 +8,6 @@
 namespace Drupal\system\Plugin\Block;
 
 use Drupal\block\BlockBase;
-use Drupal\Core\Session\AccountInterface;
 
 /**
  * Provides a generic Menu block.
@@ -30,4 +29,11 @@ public function build() {
     return menu_tree($menu);
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheKeys() {
+    return array(DRUPAL_CACHE_PER_PAGE, DRUPAL_CACHE_PER_ROLE);
+  }
+
 }
diff --git a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemPoweredByBlock.php b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemPoweredByBlock.php
index 742af7b..e5a5e63 100644
--- a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemPoweredByBlock.php
+++ b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemPoweredByBlock.php
@@ -26,4 +26,18 @@ public function build() {
     return array('#markup' => '<span>' . t('Powered by <a href="@poweredby">Drupal</a>', array('@poweredby' => 'http://drupal.org')) . '</span>');
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheMaxAge() {
+    return \Drupal\Core\Cache\Cache::PERMANENT;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isCacheable() {
+    return TRUE;
+  }
+
 }
diff --git a/core/modules/system/lib/Drupal/system/Plugin/Derivative/SystemMenuBlock.php b/core/modules/system/lib/Drupal/system/Plugin/Derivative/SystemMenuBlock.php
index 5542808..0c1d37f 100644
--- a/core/modules/system/lib/Drupal/system/Plugin/Derivative/SystemMenuBlock.php
+++ b/core/modules/system/lib/Drupal/system/Plugin/Derivative/SystemMenuBlock.php
@@ -52,7 +52,6 @@ public function getDerivativeDefinitions(array $base_plugin_definition) {
     foreach ($this->menuStorage->loadMultiple() as $menu => $entity) {
       $this->derivatives[$menu] = $base_plugin_definition;
       $this->derivatives[$menu]['admin_label'] = $entity->label();
-      $this->derivatives[$menu]['cache'] = DRUPAL_NO_CACHE;
     }
     return $this->derivatives;
   }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Cache/PageCacheTagsIntegrationTest.php b/core/modules/system/lib/Drupal/system/Tests/Cache/PageCacheTagsIntegrationTest.php
index b245c34..9c2232a 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Cache/PageCacheTagsIntegrationTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Cache/PageCacheTagsIntegrationTest.php
@@ -64,9 +64,28 @@ function testPageCacheTags() {
       'promote' => NODE_PROMOTED,
     ));
 
+    // Place a block, but only make it visible on full node page 2.
+    $block = $this->drupalPlaceBlock('views_block:comments_recent-block_1', array(
+      'visibility' => array(
+        'path' => array(
+          'visibility' => BLOCK_VISIBILITY_LISTED,
+          'pages' => 'node/' . $node_2->id(),
+        ),
+      )
+    ));
+
     // Full node page 1.
     $this->verifyPageCacheTags('node/' . $node_1->id(), array(
       'content:1',
+      'block_view:1',
+      'block:bartik_content',
+      'block:bartik_login',
+      'block:bartik_footer',
+      'block:bartik_powered',
+      'block_plugin:system_main_block',
+      'block_plugin:user_login_block',
+      'block_plugin:system_menu_block__footer',
+      'block_plugin:system_powered_by_block',
       'node_view:1',
       'node:' . $node_1->id(),
       'user:' . $author_1->id(),
@@ -78,6 +97,17 @@ function testPageCacheTags() {
     // Full node page 2.
     $this->verifyPageCacheTags('node/' . $node_2->id(), array(
       'content:1',
+      'block_view:1',
+      'block:bartik_content',
+      'block:bartik_login',
+      'block:' . $block->id(),
+      'block:bartik_footer',
+      'block:bartik_powered',
+      'block_plugin:system_main_block',
+      'block_plugin:user_login_block',
+      'block_plugin:views_block__comments_recent-block_1',
+      'block_plugin:system_menu_block__footer',
+      'block_plugin:system_powered_by_block',
       'node_view:1',
       'node:' . $node_2->id(),
       'user:' . $author_2->id(),
diff --git a/core/modules/views/lib/Drupal/views/Plugin/Block/ViewsBlock.php b/core/modules/views/lib/Drupal/views/Plugin/Block/ViewsBlock.php
index 482c25f..2648919 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/Block/ViewsBlock.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/Block/ViewsBlock.php
@@ -29,13 +29,11 @@ public function build() {
     $this->view->display_handler->preBlockBuild($this);
 
     if ($output = $this->view->executeDisplay($this->displayID)) {
-      // Set the label to the title configured in the view.
-      if (empty($this->configuration['views_label'])) {
-        $this->configuration['label'] = Xss::filterAdmin($this->view->getTitle());
-      }
-      else {
-        $this->configuration['label'] = $this->configuration['views_label'];
+      // Override the label to the dynamic title configured in the view.
+      if (empty($this->configuration['views_label']) && $this->view->getTitle()) {
+        $output['#title'] = Xss::filterAdmin($this->view->getTitle());
       }
+
       // Before returning the block output, convert it to a renderable array
       // with contextual links.
       $this->addContextualLinks($output);
@@ -48,6 +46,20 @@ public function build() {
   /**
    * {@inheritdoc}
    */
+  public function getConfiguration() {
+    $configuration = parent::getConfiguration();
+
+    // Set the label to the static title configured in the view.
+    if (!empty($configuration['views_label'])) {
+      $configuration['label'] = $configuration['views_label'];
+    }
+
+    return $configuration;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function defaultConfiguration() {
     $settings = parent::defaultConfiguration();
 
diff --git a/core/modules/views/lib/Drupal/views/Plugin/Derivative/ViewsBlock.php b/core/modules/views/lib/Drupal/views/Plugin/Derivative/ViewsBlock.php
index 30d242a..c8ba106 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/Derivative/ViewsBlock.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/Derivative/ViewsBlock.php
@@ -102,7 +102,6 @@ public function getDerivativeDefinitions(array $base_plugin_definition) {
           $this->derivatives[$delta] = array(
             'category' => $display->getOption('block_category'),
             'admin_label' => $desc,
-            'cache' => $display->getCacheType()
           );
           $this->derivatives[$delta] += $base_plugin_definition;
         }
diff --git a/core/modules/views/lib/Drupal/views/Plugin/Derivative/ViewsExposedFilterBlock.php b/core/modules/views/lib/Drupal/views/Plugin/Derivative/ViewsExposedFilterBlock.php
index 96bdd4c..a85efa3 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/Derivative/ViewsExposedFilterBlock.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/Derivative/ViewsExposedFilterBlock.php
@@ -93,7 +93,6 @@ public function getDerivativeDefinitions(array $base_plugin_definition) {
             $desc = t('Exposed form: @view-@display_id', array('@view' => $view->id(), '@display_id' => $display->display['id']));
             $this->derivatives[$delta] = array(
               'admin_label' => $desc,
-              'cache' => DRUPAL_NO_CACHE,
             );
             $this->derivatives[$delta] += $base_plugin_definition;
           }
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php
index db9eff1..c407cd7 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php
@@ -2383,7 +2383,6 @@ public function getSpecialBlocks() {
 
       $blocks[$delta] = array(
         'info' => $desc,
-        'cache' => DRUPAL_NO_CACHE,
       );
     }
 
diff --git a/core/modules/views/tests/Drupal/views/Tests/Plugin/Block/ViewsBlockTest.php b/core/modules/views/tests/Drupal/views/Tests/Plugin/Block/ViewsBlockTest.php
index 15d4d6e..d0a4d37 100644
--- a/core/modules/views/tests/Drupal/views/Tests/Plugin/Block/ViewsBlockTest.php
+++ b/core/modules/views/tests/Drupal/views/Tests/Plugin/Block/ViewsBlockTest.php
@@ -15,9 +15,6 @@
 if (!defined('BLOCK_LABEL_VISIBLE')) {
   define('BLOCK_LABEL_VISIBLE', 'visible');
 }
-if (!defined('DRUPAL_NO_CACHE')) {
-  define('DRUPAL_NO_CACHE', -1);
-}
 
 /**
  * Tests the views block plugin.
diff --git a/core/profiles/minimal/config/block.block.stark_admin.yml b/core/profiles/minimal/config/block.block.stark_admin.yml
index f3c1735..a2a51d1 100644
--- a/core/profiles/minimal/config/block.block.stark_admin.yml
+++ b/core/profiles/minimal/config/block.block.stark_admin.yml
@@ -9,7 +9,6 @@ settings:
   label: Administration
   module: system
   label_display: visible
-  cache: -1
 visibility:
   path:
     visibility: 0
diff --git a/core/profiles/minimal/config/block.block.stark_login.yml b/core/profiles/minimal/config/block.block.stark_login.yml
index 4ca8266..a4a17cc 100644
--- a/core/profiles/minimal/config/block.block.stark_login.yml
+++ b/core/profiles/minimal/config/block.block.stark_login.yml
@@ -9,7 +9,6 @@ settings:
   label: 'User login'
   module: user
   label_display: visible
-  cache: -1
 visibility:
   path:
     visibility: 0
diff --git a/core/profiles/minimal/config/block.block.stark_tools.yml b/core/profiles/minimal/config/block.block.stark_tools.yml
index a452643..648c266 100644
--- a/core/profiles/minimal/config/block.block.stark_tools.yml
+++ b/core/profiles/minimal/config/block.block.stark_tools.yml
@@ -9,7 +9,6 @@ settings:
   label: Tools
   module: system
   label_display: visible
-  cache: -1
 visibility:
   path:
     visibility: 0
diff --git a/core/profiles/standard/config/block.block.bartik_breadcrumbs.yml b/core/profiles/standard/config/block.block.bartik_breadcrumbs.yml
index 3465368..a525a35 100644
--- a/core/profiles/standard/config/block.block.bartik_breadcrumbs.yml
+++ b/core/profiles/standard/config/block.block.bartik_breadcrumbs.yml
@@ -9,7 +9,6 @@ settings:
   label: Breadcrumbs
   module: system
   label_display: '0'
-  cache: -1
 visibility:
   path:
     visibility: 0
diff --git a/core/profiles/standard/config/block.block.bartik_content.yml b/core/profiles/standard/config/block.block.bartik_content.yml
index 8146a54..537bcae 100644
--- a/core/profiles/standard/config/block.block.bartik_content.yml
+++ b/core/profiles/standard/config/block.block.bartik_content.yml
@@ -9,7 +9,6 @@ settings:
   label: 'Main page content'
   module: system
   label_display: '0'
-  cache: -1
 visibility:
   path:
     visibility: 0
diff --git a/core/profiles/standard/config/block.block.bartik_footer.yml b/core/profiles/standard/config/block.block.bartik_footer.yml
index 76f9508..4f4db57 100644
--- a/core/profiles/standard/config/block.block.bartik_footer.yml
+++ b/core/profiles/standard/config/block.block.bartik_footer.yml
@@ -9,7 +9,6 @@ settings:
   label: 'Footer menu'
   module: system
   label_display: visible
-  cache: -1
 visibility:
   path:
     visibility: 0
diff --git a/core/profiles/standard/config/block.block.bartik_help.yml b/core/profiles/standard/config/block.block.bartik_help.yml
index 5806db7..33ccc5a 100644
--- a/core/profiles/standard/config/block.block.bartik_help.yml
+++ b/core/profiles/standard/config/block.block.bartik_help.yml
@@ -9,7 +9,6 @@ settings:
   label: 'System Help'
   module: system
   label_display: '0'
-  cache: -1
 visibility:
   path:
     visibility: 0
diff --git a/core/profiles/standard/config/block.block.bartik_login.yml b/core/profiles/standard/config/block.block.bartik_login.yml
index 7fc17cb..1f96baa 100644
--- a/core/profiles/standard/config/block.block.bartik_login.yml
+++ b/core/profiles/standard/config/block.block.bartik_login.yml
@@ -9,7 +9,6 @@ settings:
   label: 'User login'
   module: user
   label_display: visible
-  cache: -1
 visibility:
   path:
     visibility: 0
diff --git a/core/profiles/standard/config/block.block.bartik_powered.yml b/core/profiles/standard/config/block.block.bartik_powered.yml
index 0e3ebab..65f24ad 100644
--- a/core/profiles/standard/config/block.block.bartik_powered.yml
+++ b/core/profiles/standard/config/block.block.bartik_powered.yml
@@ -9,7 +9,6 @@ settings:
   label: 'Powered by Drupal'
   module: system
   label_display: '0'
-  cache: -1
 visibility:
   path:
     visibility: 0
diff --git a/core/profiles/standard/config/block.block.bartik_search.yml b/core/profiles/standard/config/block.block.bartik_search.yml
index f68adbc..46279d7 100644
--- a/core/profiles/standard/config/block.block.bartik_search.yml
+++ b/core/profiles/standard/config/block.block.bartik_search.yml
@@ -9,7 +9,6 @@ settings:
   label: Search
   module: search
   label_display: visible
-  cache: -1
 visibility:
   path:
     visibility: 0
diff --git a/core/profiles/standard/config/block.block.bartik_tools.yml b/core/profiles/standard/config/block.block.bartik_tools.yml
index 257990d..d845957 100644
--- a/core/profiles/standard/config/block.block.bartik_tools.yml
+++ b/core/profiles/standard/config/block.block.bartik_tools.yml
@@ -9,7 +9,6 @@ settings:
   label: Tools
   module: system
   label_display: visible
-  cache: -1
 visibility:
   path:
     visibility: 0
diff --git a/core/profiles/standard/config/block.block.seven_breadcrumbs.yml b/core/profiles/standard/config/block.block.seven_breadcrumbs.yml
index b56f633..1a6318c 100644
--- a/core/profiles/standard/config/block.block.seven_breadcrumbs.yml
+++ b/core/profiles/standard/config/block.block.seven_breadcrumbs.yml
@@ -9,7 +9,6 @@ settings:
   label: Breadcrumbs
   module: system
   label_display: '0'
-  cache: -1
 visibility:
   path:
     visibility: 0
diff --git a/core/profiles/standard/config/block.block.seven_content.yml b/core/profiles/standard/config/block.block.seven_content.yml
index 23a6568..4f60d5e 100644
--- a/core/profiles/standard/config/block.block.seven_content.yml
+++ b/core/profiles/standard/config/block.block.seven_content.yml
@@ -9,7 +9,6 @@ settings:
   label: 'Main page content'
   module: system
   label_display: '0'
-  cache: -1
 visibility:
   path:
     visibility: 0
diff --git a/core/profiles/standard/config/block.block.seven_help.yml b/core/profiles/standard/config/block.block.seven_help.yml
index 77918e5..dcc87b7 100644
--- a/core/profiles/standard/config/block.block.seven_help.yml
+++ b/core/profiles/standard/config/block.block.seven_help.yml
@@ -9,7 +9,6 @@ settings:
   label: 'System Help'
   module: system
   label_display: '0'
-  cache: -1
 visibility:
   path:
     visibility: 0
diff --git a/core/profiles/standard/config/block.block.seven_login.yml b/core/profiles/standard/config/block.block.seven_login.yml
index 239bd36..f2602cc 100644
--- a/core/profiles/standard/config/block.block.seven_login.yml
+++ b/core/profiles/standard/config/block.block.seven_login.yml
@@ -9,7 +9,6 @@ settings:
   label: 'User login'
   module: user
   label_display: visible
-  cache: -1
 visibility:
   path:
     visibility: 0
