diff --git a/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php
index c8d76eb294..2f19f9cbb1 100644
--- a/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php
@@ -168,13 +168,18 @@ public function onRespond(ResponseEvent $event) {
 
     $is_cacheable = ($this->requestPolicy->check($request) === RequestPolicyInterface::ALLOW) && ($this->responsePolicy->check($response, $request) !== ResponsePolicyInterface::DENY);
 
+    $client_error_max_age = $this->config->get('cache.page.4xx_max_age');
+    $max_age = $response->isClientError() && isset($client_error_max_age)
+      ? $client_error_max_age
+      : $this->config->get('cache.page.max_age');
+
     // Add headers necessary to specify whether the response should be cached by
     // proxies and/or the browser.
-    if ($is_cacheable && $this->config->get('cache.page.max_age') > 0) {
+    if ($is_cacheable && $max_age > 0) {
       if (!$this->isCacheControlCustomized($response)) {
         // Only add the default Cache-Control header if the controller did not
         // specify one on the response.
-        $this->setResponseCacheable($response, $request);
+        $this->setResponseCacheable($response, $request, $max_age);
       }
     }
     else {
@@ -240,8 +245,10 @@ protected function setResponseNotCacheable(Response $response, Request $request)
    *   A response object.
    * @param \Symfony\Component\HttpFoundation\Request $request
    *   A request object.
+   * @param int $max_age
+   *   The value for the max-age Cache-Control header
    */
-  protected function setResponseCacheable(Response $response, Request $request) {
+  protected function setResponseCacheable(Response $response, Request $request, $max_age) {
     // HTTP/1.0 proxies do not support the Vary header, so prevent any caching
     // by sending an Expires date in the past. HTTP/1.1 clients ignore the
     // Expires header if a Cache-Control: max-age directive is specified (see
@@ -250,7 +257,6 @@ protected function setResponseCacheable(Response $response, Request $request) {
       $this->setExpiresNoCache($response);
     }
 
-    $max_age = $this->config->get('cache.page.max_age');
     $response->headers->set('Cache-Control', 'public, max-age=' . $max_age);
 
     // In order to support HTTP cache-revalidation, ensure that there is a
diff --git a/core/modules/page_cache/tests/src/Functional/PageCacheTest.php b/core/modules/page_cache/tests/src/Functional/PageCacheTest.php
index 13e427e59f..ffea3e120e 100644
--- a/core/modules/page_cache/tests/src/Functional/PageCacheTest.php
+++ b/core/modules/page_cache/tests/src/Functional/PageCacheTest.php
@@ -375,15 +375,20 @@ public function testPageCacheAnonymous403404() {
       404 => $invalid_url,
     ];
     $cache_ttl_4xx = Settings::get('cache_ttl_4xx', 3600);
+    $config = $this->config('system.performance');
     foreach ($tests as $code => $content_url) {
+      $config->set('cache.page.4xx_max_age', 300)->save();
       // Anonymous user, without permissions.
       $this->drupalGet($content_url);
       $this->assertSession()->statusCodeEquals($code);
       $this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'MISS');
       $this->assertSession()->responseHeaderContains('X-Drupal-Cache-Tags', '4xx-response');
+      $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'max-age=300, public');
       $this->drupalGet($content_url);
       $this->assertSession()->statusCodeEquals($code);
       $this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'HIT');
+
+      // Saving an entity clears 4xx cache tag.
       $entity_values = [
         'name' => $this->randomMachineName(),
         'user_id' => 1,
@@ -396,18 +401,28 @@ public function testPageCacheAnonymous403404() {
       ];
       $entity = EntityTest::create($entity_values);
       $entity->save();
-      // Saving an entity clears 4xx cache tag.
       $this->drupalGet($content_url);
       $this->assertSession()->statusCodeEquals($code);
       $this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'MISS');
       $this->drupalGet($content_url);
       $this->assertSession()->statusCodeEquals($code);
       $this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'HIT');
+
       // Rebuilding the router should invalidate the 4xx cache tag.
       $this->container->get('router.builder')->rebuild();
       $this->drupalGet($content_url);
       $this->assertSession()->statusCodeEquals($code);
       $this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'MISS');
+      $this->drupalGet($content_url);
+      $this->assertSession()->statusCodeEquals($code);
+      $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT');
+
+      // Setting cache.page.4xx_max_age should invalidate the 4xx cache tag.
+      $config->set('cache.page.4xx_max_age', 0)->save();
+      $this->drupalGet($content_url);
+      $this->assertSession()->statusCodeEquals($code);
+      $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS');
+      $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'must-revalidate, no-cache, private');
 
       // Ensure the 'expire' field on the cache entry uses cache_ttl_4xx.
       $cache_item = \Drupal::service('cache.page')->get($this->getUrl() . ':');
diff --git a/core/modules/system/config/install/system.performance.yml b/core/modules/system/config/install/system.performance.yml
index 11392bd1e4..75c863efa4 100644
--- a/core/modules/system/config/install/system.performance.yml
+++ b/core/modules/system/config/install/system.performance.yml
@@ -1,6 +1,7 @@
 cache:
   page:
     max_age: 0
+    4xx_max_age: null
 css:
   preprocess: true
   gzip: true
diff --git a/core/modules/system/config/schema/system.schema.yml b/core/modules/system/config/schema/system.schema.yml
index e68bbae5a8..a1da025478 100644
--- a/core/modules/system/config/schema/system.schema.yml
+++ b/core/modules/system/config/schema/system.schema.yml
@@ -152,6 +152,10 @@ system.performance:
             max_age:
               type: integer
               label: 'Max age'
+            4xx_max_age:
+              type: integer
+              nullable: true
+              label: 'Max age for 4xx responses'
     css:
       type: mapping
       label: 'CSS performance settings'
diff --git a/core/modules/system/src/SystemConfigSubscriber.php b/core/modules/system/src/SystemConfigSubscriber.php
index 0ab0d15fc6..d9bfe88c8d 100644
--- a/core/modules/system/src/SystemConfigSubscriber.php
+++ b/core/modules/system/src/SystemConfigSubscriber.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\system;
 
+use Drupal\Core\Cache\Cache;
 use Drupal\Core\Config\ConfigCrudEvent;
 use Drupal\Core\Config\ConfigEvents;
 use Drupal\Core\Config\ConfigImporterEvent;
@@ -42,6 +43,9 @@ public function onConfigSave(ConfigCrudEvent $event) {
     if ($saved_config->getName() == 'system.theme' && ($event->isChanged('admin') || $event->isChanged('default'))) {
       $this->routerBuilder->setRebuildNeeded();
     }
+    if ($saved_config->getName() === 'system.performance' && $event->isChanged('cache.page.4xx_max_age')) {
+      Cache::invalidateTags(['4xx-response']);
+    }
   }
 
   /**
diff --git a/core/modules/system/system.post_update.php b/core/modules/system/system.post_update.php
index 803f362dac..635fb43986 100644
--- a/core/modules/system/system.post_update.php
+++ b/core/modules/system/system.post_update.php
@@ -168,3 +168,12 @@ function system_post_update_schema_version_int() {
     }
   }
 }
+
+/**
+ * Set max-age for 4xx responses to null.
+ */
+function system_post_update_set_max_age_4xx() {
+  \Drupal::configFactory()->getEditable('system.performance')
+    ->set('cache.page.4xx_max_age', NULL)
+    ->save(TRUE);
+}
diff --git a/core/modules/system/tests/src/Functional/Update/AddPageCache4xxMaxAgeToSystemPerformanceConfigurationTest.php b/core/modules/system/tests/src/Functional/Update/AddPageCache4xxMaxAgeToSystemPerformanceConfigurationTest.php
new file mode 100644
index 0000000000..0f11db8689
--- /dev/null
+++ b/core/modules/system/tests/src/Functional/Update/AddPageCache4xxMaxAgeToSystemPerformanceConfigurationTest.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace Drupal\Tests\system\Functional\Update;
+
+use Drupal\FunctionalTests\Update\UpdatePathTestBase;
+
+/**
+ * Ensures cache.page.4xx_max_age is added to system.performance configuration.
+ *
+ * @group Update
+ */
+class AddPageCache4xxMaxAgeToSystemPerformanceConfigurationTest extends UpdatePathTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setDatabaseDumpFiles() {
+    $this->databaseDumpFiles = [
+      __DIR__ . '/../../../fixtures/update/drupal-8.8.0.bare.standard.php.gz',
+    ];
+  }
+
+  /**
+   * Ensures cache.page.4xx_max_age is added to system.performance
+   * configuration.
+   */
+  public function testUpdate() {
+    $system_performance = \Drupal::config('system.performance')->get();
+    $this->assertArrayNotHasKey('4xx_max_age', $system_performance['cache']['page'], 'Configuration cache.page.4xx_max_age does not exist in system.performance.');
+
+    $this->runUpdates();
+
+    $system_performance = \Drupal::config('system.performance')->get();
+    $this->assertArrayHasKey('4xx_max_age', $system_performance['cache']['page'], 'Configuration cache.page.4xx_max_age has been added to system.performance.');
+  }
+
+}
diff --git a/core/modules/system/tests/src/Kernel/Migrate/d6/MigrateSystemConfigurationTest.php b/core/modules/system/tests/src/Kernel/Migrate/d6/MigrateSystemConfigurationTest.php
index 77dba8e29b..c53fc7eb66 100644
--- a/core/modules/system/tests/src/Kernel/Migrate/d6/MigrateSystemConfigurationTest.php
+++ b/core/modules/system/tests/src/Kernel/Migrate/d6/MigrateSystemConfigurationTest.php
@@ -68,6 +68,7 @@ class MigrateSystemConfigurationTest extends MigrateDrupal6TestBase {
       'cache' => [
         'page' => [
           'max_age' => 0,
+          '4xx_max_age' => NULL,
         ],
       ],
       'css' => [
diff --git a/core/modules/system/tests/src/Kernel/Migrate/d7/MigrateSystemConfigurationTest.php b/core/modules/system/tests/src/Kernel/Migrate/d7/MigrateSystemConfigurationTest.php
index f8d37e494c..3b6d79b2ee 100644
--- a/core/modules/system/tests/src/Kernel/Migrate/d7/MigrateSystemConfigurationTest.php
+++ b/core/modules/system/tests/src/Kernel/Migrate/d7/MigrateSystemConfigurationTest.php
@@ -71,6 +71,7 @@ class MigrateSystemConfigurationTest extends MigrateDrupal7TestBase {
       'cache' => [
         'page' => [
           'max_age' => 300,
+          '4xx_max_age' => NULL,
         ],
       ],
       'css' => [
