diff --git a/core/lib/Drupal/Core/EventSubscriber/DefaultExceptionSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/DefaultExceptionSubscriber.php
index b8dc94e85c6f44520aef1392debf5682c3499d2a..e35eff42ad693f046577d333d34ac8656c759439 100644
--- a/core/lib/Drupal/Core/EventSubscriber/DefaultExceptionSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/DefaultExceptionSubscriber.php
@@ -19,6 +19,7 @@
 use Drupal\Core\Utility\Error;
 use Symfony\Component\Debug\Exception\FlattenException;
 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;
@@ -171,15 +172,12 @@ protected function onJson(GetResponseForExceptionEvent $event) {
 
     // Display the message if the current error reporting level allows this type
     // of message to be displayed,
-    $message = error_displayable($error) ? 'A fatal error occurred: ' . $exception->getMessage() : '';
-
-    // @todo We would prefer to use JsonResponse here, but existing code and
-    // tests are not prepared for parsing a JSON response when there are quotes
-    // or other values that would cause escaping issues. Instead, return a
-    // plain string and mark it as such.
-    $response = new Response($message, Response::HTTP_INTERNAL_SERVER_ERROR, [
-      'Content-type' => 'text/plain'
-    ]);
+    $data = NULL;
+    if (error_displayable($error) && $message = $exception->getMessage()) {
+      $data = ['error' => sprintf('A fatal error occurred: %s', $message)];
+    }
+
+    $response = new JsonResponse($data, Response::HTTP_INTERNAL_SERVER_ERROR);
     if ($exception instanceof HttpExceptionInterface) {
       $response->setStatusCode($exception->getStatusCode());
     }
diff --git a/core/modules/editor/src/Tests/QuickEditIntegrationLoadingTest.php b/core/modules/editor/src/Tests/QuickEditIntegrationLoadingTest.php
index 13b882a9c0657599cc0d26de4ded81806e7a1f2e..cce6e04c6bf2c0fd56eafe27297cfe0dbc86fb53 100644
--- a/core/modules/editor/src/Tests/QuickEditIntegrationLoadingTest.php
+++ b/core/modules/editor/src/Tests/QuickEditIntegrationLoadingTest.php
@@ -90,8 +90,7 @@ public function testUsersWithoutPermission() {
       // Retrieving the untransformed text should result in an empty 403 response.
       $response = $this->drupalPost('editor/' . 'node/1/body/en/full', 'application/vnd.drupal-ajax', array());
       $this->assertResponse(403);
-      // @todo Uncomment the below once https://drupal.org/node/2063303 is fixed.
-      // $this->assertIdentical('[]', $response);
+      $this->assertIdentical('{}', $response);
     }
   }
 
diff --git a/core/modules/quickedit/src/Tests/QuickEditLoadingTest.php b/core/modules/quickedit/src/Tests/QuickEditLoadingTest.php
index f795ad381945790a2ad452b505a0fb8538b1795f..a20663d8702c79f709bfb87ba3109bad093fb9eb 100644
--- a/core/modules/quickedit/src/Tests/QuickEditLoadingTest.php
+++ b/core/modules/quickedit/src/Tests/QuickEditLoadingTest.php
@@ -92,13 +92,11 @@ public function testUserWithoutPermission() {
     // able to use any of the other endpoints either.
     $post = array('editors[0]' => 'form') + $this->getAjaxPageStatePostData();
     $response = $this->drupalPost('quickedit/attachments', 'application/vnd.drupal-ajax', $post);
-    // @todo Uncomment the below once https://drupal.org/node/2063303 is fixed.
-    // $this->assertIdentical('[]', $response);
+    $this->assertIdentical('{}', $response);
     $this->assertResponse(403);
     $post = array('nocssjs' => 'true') + $this->getAjaxPageStatePostData();
     $response = $this->drupalPost('quickedit/form/' . 'node/1/body/en/full', 'application/vnd.drupal-ajax', $post);
-    // @todo Uncomment the below once https://drupal.org/node/2063303 is fixed.
-    // $this->assertIdentical('[]', $response);
+    $this->assertIdentical('{}', $response);
     $this->assertResponse(403);
     $edit = array();
     $edit['form_id'] = 'quickedit_field_form';
@@ -109,13 +107,11 @@ public function testUserWithoutPermission() {
     $edit['body[0][format]'] = 'filtered_html';
     $edit['op'] = t('Save');
     $response = $this->drupalPost('quickedit/form/' . 'node/1/body/en/full', 'application/vnd.drupal-ajax', $edit);
-    // @todo Uncomment the below once https://drupal.org/node/2063303 is fixed.
-    // $this->assertIdentical('[]', $response);
+    $this->assertIdentical('{}', $response);
     $this->assertResponse(403);
     $post = array('nocssjs' => 'true');
     $response = $this->drupalPost('quickedit/entity/' . 'node/1', 'application/json', $post);
-    // @todo Uncomment the below once https://drupal.org/node/2063303 is fixed.
-    // $this->assertIdentical('[]', $response);
+    $this->assertIdentical('{}', $response);
     $this->assertResponse(403);
   }
 
@@ -265,8 +261,6 @@ public function testUserWithPermission() {
       );
       $post += $edit + $this->getAjaxPageStatePostData();
       $response = $this->drupalPost('quickedit/form/' . 'node/1/body/en/full', 'application/vnd.drupal-ajax', $post);
-      // @todo Uncomment the below once https://drupal.org/node/2063303 is fixed.
-      // $this->assertIdentical('[]', $response);
       $this->assertResponse(200);
       $ajax_commands = Json::decode($response);
       $this->assertIdentical(1, count($ajax_commands), 'The field form HTTP request results in one AJAX command.');
@@ -276,9 +270,11 @@ public function testUserWithPermission() {
       // Save the entity.
       $post = array('nocssjs' => 'true');
       $response = $this->drupalPost('quickedit/entity/' . 'node/1', 'application/json', $post);
-      // @todo Uncomment the below once https://drupal.org/node/2063303 is fixed.
-      // $this->assertIdentical('[]', $response);
       $this->assertResponse(200);
+      $ajax_commands = Json::decode($response);
+      $this->assertIdentical(1, count($ajax_commands));
+      $this->assertIdentical('quickeditEntitySaved', $ajax_commands[0]['command'], 'The first AJAX command is an quickeditEntitySaved command.');
+      $this->assertEqual($ajax_commands[0]['data'], ['entity_type' => 'node', 'entity_id' => 1], 'Updated entity type and ID returned');
 
       // Test that a revision was created with the correct log message.
       $vids = \Drupal::entityManager()->getStorage('node')->revisionIds(node_load(1));
diff --git a/core/modules/rest/src/Tests/AuthTest.php b/core/modules/rest/src/Tests/AuthTest.php
index b53beaf9cf8534430e02d6d66a31f2ebf09b8cc1..257e7f1ee523bcc1cd82bcdb8ad9962c80a7bff6 100644
--- a/core/modules/rest/src/Tests/AuthTest.php
+++ b/core/modules/rest/src/Tests/AuthTest.php
@@ -39,7 +39,7 @@ public function testRead() {
     // Try to read the resource as an anonymous user, which should not work.
     $this->httpRequest($entity->getSystemPath(), 'GET', NULL, $this->defaultMimeType);
     $this->assertResponse('401', 'HTTP response code is 401 when the request is not authenticated and the user is anonymous.');
-    $this->assertText('A fatal error occurred: No authentication credentials provided.');
+    $this->assertRaw(json_encode(['error' => 'A fatal error occurred: No authentication credentials provided.']));
 
     // Ensure that cURL settings/headers aren't carried over to next request.
     unset($this->curlHandle);
diff --git a/core/modules/rest/src/Tests/ReadTest.php b/core/modules/rest/src/Tests/ReadTest.php
index dda6bc803bdcf85ac97e2275b8195dc49adfd01e..e1aae7fdedb0e8d3efa8ae3c1de30e4fb52b9d49 100644
--- a/core/modules/rest/src/Tests/ReadTest.php
+++ b/core/modules/rest/src/Tests/ReadTest.php
@@ -60,7 +60,9 @@ public function testRead() {
       // Try to read an entity that does not exist.
       $response = $this->httpRequest($entity_type . '/9999', 'GET', NULL, $this->defaultMimeType);
       $this->assertResponse(404);
-      $this->assertText('A fatal error occurred: The "' . $entity_type . '" parameter was not converted for the path', 'Response message is correct.');
+      $path = $entity_type == 'node' ? '/node/{node}' : '/entity_test/{entity_test}';
+      $expected_message = Json::encode(['error' => 'A fatal error occurred: The "' . $entity_type . '" parameter was not converted for the path "' . $path . '" (route name: "rest.entity.' . $entity_type . '.GET.hal_json")']);
+      $this->assertIdentical($expected_message, $response, 'Response message is correct.');
 
       // Make sure that field level access works and that the according field is
       // not available in the response. Only applies to entity_test.
@@ -79,14 +81,15 @@ public function testRead() {
       $this->drupalLogout();
       $response = $this->httpRequest($entity->getSystemPath(), 'GET', NULL, $this->defaultMimeType);
       $this->assertResponse(403);
-      $this->assertNull(Json::decode($response), 'No valid JSON found.');
+      $this->assertIdentical('{}', $response);
     }
     // Try to read a resource which is not REST API enabled.
     $account = $this->drupalCreateUser();
     $this->drupalLogin($account);
     $response = $this->httpRequest($account->getSystemPath(), 'GET', NULL, $this->defaultMimeType);
     $this->assertResponse(404);
-    $this->assertNull(Json::decode($response), 'No valid JSON found.');
+    $expected_message = Json::encode(['error' => 'A fatal error occurred: Unable to find the controller for path "/user/4". Maybe you forgot to add the matching route in your routing configuration?']);
+    $this->assertIdentical($expected_message, $response);
   }
 
   /**