diff --git a/core/lib/Drupal/Core/EventSubscriber/CacheRouterRebuildSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/CacheRouterRebuildSubscriber.php
index 38007f5..8e8e885 100644
--- a/core/lib/Drupal/Core/EventSubscriber/CacheRouterRebuildSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/CacheRouterRebuildSubscriber.php
@@ -4,6 +4,7 @@
 
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Routing\RoutingEvents;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 
 /**
@@ -16,8 +17,8 @@ class CacheRouterRebuildSubscriber implements EventSubscriberInterface {
    */
   public function onRouterFinished() {
     // Requested URLs that formerly gave a 403/404 may now be valid.
-    // Also invalidate all cached routing.
-    Cache::invalidateTags(['4xx-response', 'route_match']);
+    // Also invalidate all cached routing as well as every HTTP response.
+    Cache::invalidateTags(['4xx-response', 'route_match', 'http_response']);
   }
 
   /**
diff --git a/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php
index 3db181a..418cb59 100644
--- a/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php
@@ -139,7 +139,12 @@ public function onRespond(FilterResponseEvent $event) {
       // Expose the cache contexts and cache tags associated with this page in a
       // X-Drupal-Cache-Contexts and X-Drupal-Cache-Tags header respectively.
       $response_cacheability = $response->getCacheableMetadata();
-      $response->headers->set('X-Drupal-Cache-Tags', implode(' ', $response_cacheability->getCacheTags()));
+      $tags = $response_cacheability->getCacheTags();
+      // Always add the 'http_response' cache tag to be able to invalidate every
+      // response.
+      $tags[] = 'http_response';
+
+      $response->headers->set('X-Drupal-Cache-Tags', implode(' ', $tags));
       $response->headers->set('X-Drupal-Cache-Contexts', implode(' ', $this->cacheContextsManager->optimizeTokens($response_cacheability->getCacheContexts())));
     }
 
diff --git a/core/modules/rest/src/Entity/RestResourceConfig.php b/core/modules/rest/src/Entity/RestResourceConfig.php
index bb83584..60fe55a 100644
--- a/core/modules/rest/src/Entity/RestResourceConfig.php
+++ b/core/modules/rest/src/Entity/RestResourceConfig.php
@@ -3,6 +3,7 @@
 namespace Drupal\rest\Entity;
 
 use Drupal\Core\Config\Entity\ConfigEntityBase;
+use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Plugin\DefaultSingleLazyPluginCollection;
 use Drupal\rest\RestResourceConfigInterface;
 
@@ -255,4 +256,13 @@ protected function normalizeRestMethod($method) {
     return strtoupper($method);
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function postSave(EntityStorageInterface $storage, $update = TRUE) {
+    parent::postSave($storage, $update);
+
+    \Drupal::service('router.builder')->setRebuildNeeded();
+  }
+
 }
diff --git a/core/modules/rest/src/Tests/RESTTestBase.php b/core/modules/rest/src/Tests/RESTTestBase.php
index 271df51..405493b 100644
--- a/core/modules/rest/src/Tests/RESTTestBase.php
+++ b/core/modules/rest/src/Tests/RESTTestBase.php
@@ -420,8 +420,7 @@ protected function enableService($resource_type, $method = 'GET', $format = NULL
    * Rebuilds routing caches.
    */
   protected function rebuildCache() {
-    // Rebuild routing cache, so that the REST API paths are available.
-    $this->container->get('router.builder')->rebuild();
+    $this->container->get('router.builder')->rebuildIfNeeded();
   }
 
   /**
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php b/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php
index 48ed438..17e9091 100644
--- a/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php
+++ b/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php
@@ -196,9 +196,6 @@ public function setUp() {
       }
       $this->entity->save();
     }
-
-    // @todo Remove this in https://www.drupal.org/node/2815845.
-    drupal_flush_all_caches();
   }
 
   /**
@@ -251,6 +248,7 @@ protected function getNormalizedPatchEntity() {
   protected function getExpectedCacheTags() {
     $expected_cache_tags = [
       'config:rest.resource.entity.' . static::$entityTypeId,
+      'http_response',
     ];
     if (!static::$auth) {
       $expected_cache_tags[] = 'config:user.role.anonymous';
diff --git a/core/modules/rest/tests/src/Functional/ResourceTestBase.php b/core/modules/rest/tests/src/Functional/ResourceTestBase.php
index 49ef8e5..1dc7e96 100644
--- a/core/modules/rest/tests/src/Functional/ResourceTestBase.php
+++ b/core/modules/rest/tests/src/Functional/ResourceTestBase.php
@@ -152,8 +152,7 @@ protected function provisionResource($resource_type, $formats = [], $authenticat
         'authentication' => $authentication,
       ]
     ])->save();
-    // @todo Remove this in https://www.drupal.org/node/2815845.
-    drupal_flush_all_caches();
+    \Drupal::service('router.builder')->rebuild();
   }
 
   /**
diff --git a/core/modules/search/src/Tests/SearchPageCacheTagsTest.php b/core/modules/search/src/Tests/SearchPageCacheTagsTest.php
index 3a7bc67..8dabbc7 100644
--- a/core/modules/search/src/Tests/SearchPageCacheTagsTest.php
+++ b/core/modules/search/src/Tests/SearchPageCacheTagsTest.php
@@ -190,10 +190,8 @@ public function testSearchTagsBubbling() {
       'node:2',
       'user:3',
       'node_view',
-      'config:filter.format.plain_text',
     ]);
-    $cache_tags = $this->drupalGetHeader('X-Drupal-Cache-Tags');
-    $this->assertEqual(explode(' ', $cache_tags), $expected_cache_tags);
+    $this->assertCacheTags($expected_cache_tags);
 
     // Only get the new node in the search results, should result in node:1,
     // node:2 and user:3 as cache tags even though only node:1 is shown. This is
@@ -208,8 +206,7 @@ public function testSearchTagsBubbling() {
       'user:3',
       'node_view',
     ]);
-    $cache_tags = $this->drupalGetHeader('X-Drupal-Cache-Tags');
-    $this->assertEqual(explode(' ', $cache_tags), $expected_cache_tags);
+    $this->assertCacheTags($expected_cache_tags);
   }
 
 }
diff --git a/core/modules/system/src/Tests/Cache/AssertPageCacheContextsAndTagsTrait.php b/core/modules/system/src/Tests/Cache/AssertPageCacheContextsAndTagsTrait.php
index 94ea1ac..2cad744 100644
--- a/core/modules/system/src/Tests/Cache/AssertPageCacheContextsAndTagsTrait.php
+++ b/core/modules/system/src/Tests/Cache/AssertPageCacheContextsAndTagsTrait.php
@@ -124,6 +124,7 @@ protected function assertCacheTags(array $expected_tags, $include_default_tags =
     // The anonymous role cache tag is only added if the user is anonymous.
     if ($include_default_tags && \Drupal::currentUser()->isAnonymous()) {
       $expected_tags = Cache::mergeTags($expected_tags, ['config:user.role.anonymous']);
+      $expected_tags[] = 'http_response';
     }
     $actual_tags = $this->getCacheHeaderValues('X-Drupal-Cache-Tags');
     sort($expected_tags);
diff --git a/core/modules/system/src/Tests/Routing/RouterTest.php b/core/modules/system/src/Tests/Routing/RouterTest.php
index 1b33baf..49300c0 100644
--- a/core/modules/system/src/Tests/Routing/RouterTest.php
+++ b/core/modules/system/src/Tests/Routing/RouterTest.php
@@ -45,7 +45,7 @@ public function testFinishResponseSubscriber() {
     // Check expected headers from FinishResponseSubscriber.
     $headers = $this->drupalGetHeaders();
     $this->assertEqual($headers['x-drupal-cache-contexts'], implode(' ', $expected_cache_contexts));
-    $this->assertEqual($headers['x-drupal-cache-tags'], 'config:user.role.anonymous rendered');
+    $this->assertEqual($headers['x-drupal-cache-tags'], 'config:user.role.anonymous rendered http_response');
     // Confirm that the page wrapping is being added, so we're not getting a
     // raw body returned.
     $this->assertRaw('</html>', 'Page markup was found.');
@@ -60,12 +60,12 @@ public function testFinishResponseSubscriber() {
     $this->drupalGet('router_test/test18');
     $headers = $this->drupalGetHeaders();
     $this->assertEqual($headers['x-drupal-cache-contexts'], implode(' ', Cache::mergeContexts($renderer_required_cache_contexts, ['url'])));
-    $this->assertEqual($headers['x-drupal-cache-tags'], 'config:user.role.anonymous foo rendered');
+    $this->assertEqual($headers['x-drupal-cache-tags'], 'config:user.role.anonymous foo rendered http_response');
     // 2. controller result: render array, per-role cacheable route access.
     $this->drupalGet('router_test/test19');
     $headers = $this->drupalGetHeaders();
     $this->assertEqual($headers['x-drupal-cache-contexts'], implode(' ', Cache::mergeContexts($renderer_required_cache_contexts, ['url', 'user.roles'])));
-    $this->assertEqual($headers['x-drupal-cache-tags'], 'config:user.role.anonymous foo rendered');
+    $this->assertEqual($headers['x-drupal-cache-tags'], 'config:user.role.anonymous foo rendered http_response');
     // 3. controller result: Response object, globally cacheable route access.
     $this->drupalGet('router_test/test1');
     $headers = $this->drupalGetHeaders();
