diff --git a/core/lib/Drupal/Core/Render/RenderCache.php b/core/lib/Drupal/Core/Render/RenderCache.php
index 12d52e9..b1e7666 100644
--- a/core/lib/Drupal/Core/Render/RenderCache.php
+++ b/core/lib/Drupal/Core/Render/RenderCache.php
@@ -68,14 +68,29 @@ public function get(array $elements) {
     }
     $bin = isset($elements['#cache']['bin']) ? $elements['#cache']['bin'] : 'render';
 
-    if (!empty($cid) && ($cache_bin = $this->cacheFactory->get($bin)) && $cache = $cache_bin->get($cid)) {
+    if (!empty($cid) && ($cache_bin = $this->cacheFactory->get($bin)) && $cache = $cache_bin->get($cid, TRUE)) {
+
       $cached_element = $cache->data;
+
+      // Check if the cache item was invalidated and if so, only return it
+      // if a min-age was set and has not expired.
+      if (!$cache->valid) {
+        if (!isset($elements['#cache']['min-age'])) {
+          return FALSE;
+        }
+        if ($cache->created + $elements['#cache']['min-age'] < $this->requestStack->getMasterRequest()->server->get('REQUEST_TIME')) {
+          return FALSE;
+        }
+        $cached_element['#cache']['min-age'] = $elements['#cache']['min-age'];
+      }
+
       // Two-tier caching: redirect to actual (post-bubbling) cache item.
       // @see \Drupal\Core\Render\RendererInterface::render()
       // @see ::set()
       if (isset($cached_element['#cache_redirect'])) {
         return $this->get($cached_element);
       }
+
       // Return the cached element.
       return $cached_element;
     }
@@ -329,6 +344,10 @@ public function getCacheableRenderArray(array $elements) {
       ],
     ];
 
+    if (isset($elements['#cache']['min-age'])) {
+      $data['#cache']['min-age'] = $elements['#cache']['min-age'];
+    }
+
     // Preserve cacheable items if specified. If we are preserving any cacheable
     // children of the element, we assume we are only interested in their
     // individual markup and not the parent's one, thus we empty it to minimize
diff --git a/core/modules/views/src/Plugin/Block/ViewsBlockBase.php b/core/modules/views/src/Plugin/Block/ViewsBlockBase.php
index 4a814d7..2d3120d 100644
--- a/core/modules/views/src/Plugin/Block/ViewsBlockBase.php
+++ b/core/modules/views/src/Plugin/Block/ViewsBlockBase.php
@@ -21,7 +21,7 @@
    *
    * @var \Drupal\views\ViewExecutable
    */
-  protected $view;
+  public $view;
 
   /**
    * The display ID being used for this View.
diff --git a/core/modules/views/views.module b/core/modules/views/views.module
index e1a4d8c..d3c8028 100644
--- a/core/modules/views/views.module
+++ b/core/modules/views/views.module
@@ -12,7 +12,9 @@
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Url;
+use Drupal\views\Plugin\Block\ViewsBlock;
 use Drupal\views\Plugin\Derivative\ViewsLocalTask;
+use Drupal\views\Plugin\views\cache\Time;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Entity\View;
 use Drupal\views\Render\ViewsRenderPipelineMarkup;
@@ -828,3 +830,15 @@ function views_view_delete(EntityInterface $entity) {
     }
   }
 }
+
+/**
+ * Implements hook_block_view_BASE_BLOCK_ID_alter().
+ */
+function views_block_build_views_block_alter(array &$build, \Drupal\Core\Block\BlockPluginInterface $block) {
+  if ($block instanceof ViewsBlock) {
+    $cache = $block->view->getDisplay()->getPlugin('cache');
+    if ($cache instanceof Time) {
+      $build['#cache']['min-age'] = $cache->getCacheMaxAge();
+    }
+  }
+}
diff --git a/core/tests/Drupal/Tests/Core/Render/RendererTest.php b/core/tests/Drupal/Tests/Core/Render/RendererTest.php
index 51cfde8..b611b45 100644
--- a/core/tests/Drupal/Tests/Core/Render/RendererTest.php
+++ b/core/tests/Drupal/Tests/Core/Render/RendererTest.php
@@ -726,6 +726,64 @@ public function providerTestRenderCacheMaxAge() {
   }
 
   /**
+   * @covers ::render
+   * @covers ::doRender
+   * @covers \Drupal\Core\Render\RenderCache::get
+   * @covers \Drupal\Core\Render\RenderCache::set
+   * @covers \Drupal\Core\Render\RenderCache::createCacheID
+   *
+   * @dataProvider providerTestRenderCacheMinAge
+   */
+  public function testRenderCacheMinAge($min_age, $is_render_cached, $request_time_offset) {
+
+    // Simulate that cache items were written N seconds ago.
+    $_SERVER['REQUEST_TIME'] = $_SERVER['REQUEST_TIME'] - $request_time_offset;
+
+    $this->setUpRequest();
+    $this->setupMemoryCache();
+
+    $element = [
+      '#cache' => [
+        'keys' => ['render_cache_test'],
+        'tags' => ['test'],
+        'contexts' => [],
+        'max-age' => Cache::PERMANENT,
+      ],
+      '#attached' => [],
+      '#markup' => '',
+    ];
+
+    if ($min_age) {
+      $element['#cache']['min-age'] = $min_age;
+    }
+
+    $this->renderCache->set($element, $element);
+
+    $this->memoryCache->invalidateTags(['test']);
+
+    // Revert the request time back to the current time by adding the offset
+    // again.
+    $_SERVER['REQUEST_TIME'] = $_SERVER['REQUEST_TIME'] + $request_time_offset;
+    $this->requestStack->getMasterRequest()->server->set('REQUEST_TIME', (int) $_SERVER['REQUEST_TIME']);
+
+    $cached_element = $this->renderCache->get($element);
+    if (!$is_render_cached) {
+      $this->assertFalse($cached_element);
+    }
+    else {
+      $this->assertNotFalse($cached_element);
+    }
+  }
+
+  public function providerTestRenderCacheMinAge() {
+    return [
+      [NULL, FALSE, 0],
+      [60, TRUE, 30],
+      [60, FALSE, 61],
+    ];
+  }
+
+  /**
    * Tests that #cache_properties are properly handled.
    *
    * @param array $expected_results
diff --git a/core/tests/Drupal/Tests/Core/Render/RendererTestBase.php b/core/tests/Drupal/Tests/Core/Render/RendererTestBase.php
index 964898c..683a560 100644
--- a/core/tests/Drupal/Tests/Core/Render/RendererTestBase.php
+++ b/core/tests/Drupal/Tests/Core/Render/RendererTestBase.php
@@ -82,7 +82,7 @@
   protected $elementInfo;
 
   /**
-   * @var \Drupal\Core\Cache\CacheBackendInterface
+   * @var \Drupal\Core\Cache\MemoryBackend
    */
   protected $memoryCache;
 
