diff --git a/core/lib/Drupal/Core/EventSubscriber/DefaultExceptionSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/DefaultExceptionSubscriber.php
index 4737e8031a4854e20de698f6512b9c027530b948..7b5ecc1280afea161487c4399d55c158b132c045 100644
--- a/core/lib/Drupal/Core/EventSubscriber/DefaultExceptionSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/DefaultExceptionSubscriber.php
@@ -7,7 +7,6 @@
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\Core\Utility\Error;
 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-use Symfony\Component\HttpFoundation\JsonResponse;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
@@ -119,7 +118,7 @@ protected function onHtml(GetResponseForExceptionEvent $event) {
 
     $content = $this->t('The website encountered an unexpected error. Please try again later.');
     $content .= $message ? '</br></br>' . $message : '';
-    $response = new Response($content, 500);
+    $response = new Response($content, 500, ['Content-Type' => 'text/plain']);
 
     if ($exception instanceof HttpExceptionInterface) {
       $response->setStatusCode($exception->getStatusCode());
@@ -132,34 +131,6 @@ protected function onHtml(GetResponseForExceptionEvent $event) {
     $event->setResponse($response);
   }
 
-  /**
-   * Handles any exception as a generic error page for JSON.
-   *
-   * @todo This should probably check the error reporting level.
-   *
-   * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event
-   *   The event to process.
-   */
-  protected function onJson(GetResponseForExceptionEvent $event) {
-    $exception = $event->getException();
-    $error = Error::decodeException($exception);
-
-    // Display the message if the current error reporting level allows this type
-    // of message to be displayed,
-    $data = NULL;
-    if (error_displayable($error) && $message = $exception->getMessage()) {
-      $data = ['message' => sprintf('A fatal error occurred: %s', $message)];
-    }
-
-    $response = new JsonResponse($data, Response::HTTP_INTERNAL_SERVER_ERROR);
-    if ($exception instanceof HttpExceptionInterface) {
-      $response->setStatusCode($exception->getStatusCode());
-      $response->headers->add($exception->getHeaders());
-    }
-
-    $event->setResponse($response);
-  }
-
   /**
    * Handles an HttpExceptionInterface exception for unknown formats.
    *
@@ -218,16 +189,6 @@ protected function getFormat(Request $request) {
       $format = 'json';
     }
 
-    // Make an educated guess that any Accept header type that includes "json"
-    // can probably handle a generic JSON response for errors. As above, for
-    // any format this doesn't catch or that wants custom handling should
-    // register its own exception listener.
-    foreach ($request->getAcceptableContentTypes() as $mime) {
-      if (strpos($mime, 'html') === FALSE && strpos($mime, 'json') !== FALSE) {
-        $format = 'json';
-      }
-    }
-
     return $format;
   }
 
diff --git a/core/lib/Drupal/Core/EventSubscriber/ExceptionJsonSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ExceptionJsonSubscriber.php
index 76cc55ee3abcb573aa5c26dfbd605032d14bf27b..6ccb743356de49dc3c874a7e1ca707ae313a4f6b 100644
--- a/core/lib/Drupal/Core/EventSubscriber/ExceptionJsonSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/ExceptionJsonSubscriber.php
@@ -14,7 +14,7 @@ class ExceptionJsonSubscriber extends HttpExceptionSubscriberBase {
    * {@inheritdoc}
    */
   protected function getHandledFormats() {
-    return ['json'];
+    return ['json', 'drupal_modal', 'drupal_dialog', 'drupal_ajax'];
   }
 
   /**
diff --git a/core/modules/editor/src/Tests/QuickEditIntegrationLoadingTest.php b/core/modules/editor/src/Tests/QuickEditIntegrationLoadingTest.php
index 9b9d13c5884935fe98448a7914b0ebd13b7ed7d6..c827450aeb089d598141d6e178de93fabd1dc205 100644
--- a/core/modules/editor/src/Tests/QuickEditIntegrationLoadingTest.php
+++ b/core/modules/editor/src/Tests/QuickEditIntegrationLoadingTest.php
@@ -89,12 +89,12 @@ public function testUsersWithoutPermission() {
       $response = $this->drupalPost('editor/' . 'node/1/body/en/full', '', array(), array('query' => array(MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_ajax')));
       $this->assertResponse(403);
       if (!$user->hasPermission('access in-place editing')) {
-        $message = "A fatal error occurred: The 'access in-place editing' permission is required.";
-        $this->assertIdentical(Json::encode(['message' => $message]), $response);
+        $message = "The 'access in-place editing' permission is required.";
       }
       else {
-        $this->assertIdentical('{}', $response);
+        $message = '';
       }
+      $this->assertIdentical(Json::encode(['message' => $message]), $response);
     }
   }
 
diff --git a/core/modules/quickedit/src/Tests/QuickEditLoadingTest.php b/core/modules/quickedit/src/Tests/QuickEditLoadingTest.php
index ab66227ad1ae3f09d15ae3aec220cb30caee5970..1570a27ad7d11d8ad00d2affef2929cc4eafa442 100644
--- a/core/modules/quickedit/src/Tests/QuickEditLoadingTest.php
+++ b/core/modules/quickedit/src/Tests/QuickEditLoadingTest.php
@@ -115,12 +115,12 @@ public function testUserWithoutPermission() {
     $this->assertIdentical(Json::encode(['message' => "The 'access in-place editing' permission is required."]), $response);
     $this->assertResponse(403);
 
-    // Quick Edit's JavaScript would SearchRankingTestnever hit these endpoints if the metadata
+    // Quick Edit's JavaScript would never hit these endpoints if the metadata
     // was empty as above, but we need to make sure that malicious users aren't
     // able to use any of the other endpoints either.
     $post = array('editors[0]' => 'form') + $this->getAjaxPageStatePostData();
     $response = $this->drupalPost('quickedit/attachments', '', $post, ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_ajax']]);
-    $message = Json::encode(['message' => "A fatal error occurred: The 'access in-place editing' permission is required."]);
+    $message = Json::encode(['message' => "The 'access in-place editing' permission is required."]);
     $this->assertIdentical($message, $response);
     $this->assertResponse(403);
     $post = array('nocssjs' => 'true') + $this->getAjaxPageStatePostData();
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/Comment/CommentResourceTestBase.php b/core/modules/rest/tests/src/Functional/EntityResource/Comment/CommentResourceTestBase.php
index 63991311a90a6e86accac3a54900032c019c9049..b04da54373e8e6ebbe1cbf6ba2ce894a19bd6579 100644
--- a/core/modules/rest/tests/src/Functional/EntityResource/Comment/CommentResourceTestBase.php
+++ b/core/modules/rest/tests/src/Functional/EntityResource/Comment/CommentResourceTestBase.php
@@ -280,8 +280,8 @@ public function testPostDxWithoutCriticalBaseFields() {
     $response = $this->request('POST', $url, $request_options);
     // @todo Uncomment, remove next 3 lines in https://www.drupal.org/node/2820364.
     $this->assertSame(500, $response->getStatusCode());
-    $this->assertSame(['application/json'], $response->getHeader('Content-Type'));
-    $this->assertSame('{"message":"A fatal error occurred: Internal Server Error"}', (string) $response->getBody());
+    $this->assertSame(['text/plain; charset=UTF-8'], $response->getHeader('Content-Type'));
+    $this->assertSame('Internal Server Error', (string) $response->getBody());
     //$this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\nentity_type: This value should not be null.\n", $response);
 
     // DX: 422 when missing 'entity_id' field.
@@ -303,10 +303,9 @@ public function testPostDxWithoutCriticalBaseFields() {
     // DX: 422 when missing 'entity_type' field.
     $request_options[RequestOptions::BODY] = $this->serializer->encode(array_diff_key($this->getNormalizedPostEntity(), ['field_name' => TRUE]), static::$format);
     $response = $this->request('POST', $url, $request_options);
-    // @todo Uncomment, remove next 3 lines in https://www.drupal.org/node/2820364.
+    // @todo Uncomment, remove next 2 lines in https://www.drupal.org/node/2820364.
     $this->assertSame(500, $response->getStatusCode());
-    $this->assertSame(['application/json'], $response->getHeader('Content-Type'));
-    $this->assertSame('{"message":"A fatal error occurred: Field  is unknown."}', (string) $response->getBody());
+    $this->assertSame(['text/plain; charset=UTF-8'], $response->getHeader('Content-Type'));
     //$this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\nfield_name: This value should not be null.\n", $response);
   }
 
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php b/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php
index 339af6ba162451dd888a9324540c67f46a809fc0..c7bcb97167074f49971464a25d36074a29308dc8 100644
--- a/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php
+++ b/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php
@@ -5,7 +5,6 @@
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Config\Entity\ConfigEntityInterface;
-use Drupal\Core\Entity\EntityChangedInterface;
 use Drupal\Core\Entity\FieldableEntityInterface;
 use Drupal\Core\Url;
 use Drupal\field\Entity\FieldConfig;
@@ -487,17 +486,17 @@ public function testGet() {
     // DX: 406 when requesting unsupported format.
     $response = $this->request('GET', $url, $request_options);
     $this->assert406Response($response);
-    $this->assertNotSame([static::$mimeType], $response->getHeader('Content-Type'));
+    $this->assertSame(['text/plain; charset=UTF-8'], $response->getHeader('Content-Type'));
 
 
     $request_options[RequestOptions::HEADERS]['Accept'] = static::$mimeType;
 
 
-    // DX: 406 when requesting unsupported format but specifying Accept header.
-    // @todo Update in https://www.drupal.org/node/2825347.
+    // DX: 406 when requesting unsupported format but specifying Accept header:
+    // should result in a text/plain response.
     $response = $this->request('GET', $url, $request_options);
     $this->assert406Response($response);
-    $this->assertSame(['application/json'], $response->getHeader('Content-Type'));
+    $this->assertSame(['text/plain; charset=UTF-8'], $response->getHeader('Content-Type'));
 
 
     $url = Url::fromRoute('rest.entity.' . static::$entityTypeId . '.GET.' . static::$format);
@@ -566,11 +565,11 @@ public function testPost() {
     $url->setOption('query', []);
 
 
-    // DX: 415 when no Content-Type request header, but HTML if canonical route.
+    // DX: 415 when no Content-Type request header, plain text if canonical URL.
     $response = $this->request('POST', $url, $request_options);
     if ($has_canonical_url) {
       $this->assertSame(415, $response->getStatusCode());
-      $this->assertSame(['text/html; charset=UTF-8'], $response->getHeader('Content-Type'));
+      $this->assertSame(['text/plain; charset=UTF-8'], $response->getHeader('Content-Type'));
       $this->assertContains(htmlspecialchars('No "Content-Type" request header specified'), (string) $response->getBody());
     }
     else {
@@ -728,12 +727,12 @@ public function testPatch() {
     $request_options = [];
 
 
-    // DX: 405 when resource not provisioned, but HTML if canonical route.
+    // DX: 404 when resource not provisioned, but 405 if canonical route.
     $response = $this->request('PATCH', $url, $request_options);
     if ($has_canonical_url) {
       $this->assertSame(405, $response->getStatusCode());
       $this->assertSame(['GET, POST, HEAD'], $response->getHeader('Allow'));
-      $this->assertSame(['text/html; charset=UTF-8'], $response->getHeader('Content-Type'));
+      $this->assertSame(['text/plain; charset=UTF-8'], $response->getHeader('Content-Type'));
     }
     else {
       $this->assertResourceErrorResponse(404, 'No route found for "PATCH ' . str_replace($this->baseUrl, '', $this->getUrl()->setAbsolute()->toString()) . '"', $response);
@@ -758,7 +757,7 @@ public function testPatch() {
     $response = $this->request('PATCH', $url, $request_options);
     if ($has_canonical_url) {
       $this->assertSame(415, $response->getStatusCode());
-      $this->assertSame(['text/html; charset=UTF-8'], $response->getHeader('Content-Type'));
+      $this->assertSame(['text/plain; charset=UTF-8'], $response->getHeader('Content-Type'));
       $this->assertTrue(FALSE !== strpos((string) $response->getBody(), htmlspecialchars('No "Content-Type" request header specified')));
     }
     else {
@@ -922,12 +921,12 @@ public function testDelete() {
     $request_options = [];
 
 
-    // DX: 405 when resource not provisioned, but HTML if canonical route.
+    // DX: 404 when resource not provisioned, but 405 if canonical route.
     $response = $this->request('DELETE', $url, $request_options);
     if ($has_canonical_url) {
       $this->assertSame(405, $response->getStatusCode());
       $this->assertSame(['GET, POST, HEAD'], $response->getHeader('Allow'));
-      $this->assertSame(['text/html; charset=UTF-8'], $response->getHeader('Content-Type'));
+      $this->assertSame(['text/plain; charset=UTF-8'], $response->getHeader('Content-Type'));
     }
     else {
       $this->assertResourceErrorResponse(404, 'No route found for "DELETE ' . str_replace($this->baseUrl, '', $this->getUrl()->setAbsolute()->toString()) . '"', $response);
diff --git a/core/tests/Drupal/KernelTests/Core/Routing/ExceptionHandlingTest.php b/core/tests/Drupal/KernelTests/Core/Routing/ExceptionHandlingTest.php
index 85649484bb7f24d8d339237c24596a092bd8e895..f7e60746eab082369b92a47c1ac56052210b800f 100644
--- a/core/tests/Drupal/KernelTests/Core/Routing/ExceptionHandlingTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Routing/ExceptionHandlingTest.php
@@ -155,7 +155,7 @@ public function testBacktraceEscaping() {
     $kernel = \Drupal::getContainer()->get('http_kernel');
     $response = $kernel->handle($request)->prepare($request);
     $this->assertEqual($response->getStatusCode(), Response::HTTP_INTERNAL_SERVER_ERROR);
-    $this->assertEqual($response->headers->get('Content-type'), 'text/html; charset=UTF-8');
+    $this->assertEqual($response->headers->get('Content-type'), 'text/plain; charset=UTF-8');
 
     // Test both that the backtrace is properly escaped, and that the unescaped
     // string is not output at all.
@@ -178,7 +178,7 @@ public function testExceptionEscaping() {
     $kernel = \Drupal::getContainer()->get('http_kernel');
     $response = $kernel->handle($request)->prepare($request);
     $this->assertEqual($response->getStatusCode(), Response::HTTP_INTERNAL_SERVER_ERROR);
-    $this->assertEqual($response->headers->get('Content-type'), 'text/html; charset=UTF-8');
+    $this->assertEqual($response->headers->get('Content-type'), 'text/plain; charset=UTF-8');
 
     // Test message is properly escaped, and that the unescaped string is not
     // output at all.