diff --git a/core/modules/hal/tests/src/Functional/EntityResource/HalEntityNormalizationTrait.php b/core/modules/hal/tests/src/Functional/EntityResource/HalEntityNormalizationTrait.php
index cefe7438201b838fd83b3a10f6a1f68b3e1c72e6..18655727ba628a42070a0f75ef18029f19b96d47 100644
--- a/core/modules/hal/tests/src/Functional/EntityResource/HalEntityNormalizationTrait.php
+++ b/core/modules/hal/tests/src/Functional/EntityResource/HalEntityNormalizationTrait.php
@@ -101,18 +101,18 @@ protected function assertNormalizationEdgeCases($method, Url $url, array $reques
       $normalization['_links']['type'] = Url::fromUri('base:rest/type/' . static::$entityTypeId . '/bad_bundle_name');
       $request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
 
-      // DX: 400 when incorrect entity type bundle is specified.
+      // DX: 422 when incorrect entity type bundle is specified.
       $response = $this->request($method, $url, $request_options);
-      $this->assertResourceErrorResponse(400, 'No entity type(s) specified', $response);
+      $this->assertResourceErrorResponse(422, 'No entity type(s) specified', $response);
 
 
       unset($normalization['_links']['type']);
       $request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
 
 
-      // DX: 400 when no entity type bundle is specified.
+      // DX: 422 when no entity type bundle is specified.
       $response = $this->request($method, $url, $request_options);
-      $this->assertResourceErrorResponse(400, 'The type link relation must be specified.', $response);
+      $this->assertResourceErrorResponse(422, 'The type link relation must be specified.', $response);
     }
   }
 
diff --git a/core/modules/rest/src/RequestHandler.php b/core/modules/rest/src/RequestHandler.php
index 0e9f41bbab484ebcad61efe3a1686d3819e5aca5..d7a6be71afb6270611e0fef8e97a00a4017cc39c 100644
--- a/core/modules/rest/src/RequestHandler.php
+++ b/core/modules/rest/src/RequestHandler.php
@@ -11,8 +11,10 @@
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
+use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
 use Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException;
 use Symfony\Component\Serializer\Exception\UnexpectedValueException;
+use Symfony\Component\Serializer\Exception\InvalidArgumentException;
 
 /**
  * Acts as intermediate request forwarder for resource plugins.
@@ -96,19 +98,32 @@ public function handle(RouteMatchInterface $route_match, Request $request) {
       $request_method = $request->getMethod();
       if (in_array($format, $resource_config->getFormats($request_method))) {
         $definition = $resource->getPluginDefinition();
+
+        // First decode the request data. We can then determine if the
+        // serialized data was malformed.
         try {
-          if (!empty($definition['serialization_class'])) {
-            $unserialized = $serializer->deserialize($received, $definition['serialization_class'], $format, array('request_method' => $method));
-          }
-          // If the plugin does not specify a serialization class just decode
-          // the received data.
-          else {
-            $unserialized = $serializer->decode($received, $format, array('request_method' => $method));
-          }
+          $unserialized = $serializer->decode($received, $format, ['request_method' => $method]);
         }
         catch (UnexpectedValueException $e) {
+          // If an exception was thrown at this stage, there was a problem
+          // decoding the data. Throw a 400 http exception.
           throw new BadRequestHttpException($e->getMessage());
         }
+
+        // Then attempt to denormalize if there is a serialization class.
+        if (!empty($definition['serialization_class'])) {
+          try {
+            $unserialized = $serializer->denormalize($unserialized, $definition['serialization_class'], $format, ['request_method' => $method]);
+          }
+          // These two serialization exception types mean there was a problem
+          // with the structure of the decoded data and it's not valid.
+          catch (UnexpectedValueException $e) {
+            throw new UnprocessableEntityHttpException($e->getMessage());
+          }
+          catch (InvalidArgumentException $e) {
+            throw new UnprocessableEntityHttpException($e->getMessage());
+          }
+        }
       }
       else {
         throw new UnsupportedMediaTypeHttpException();
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php b/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php
index 73dfc628daae5160540ace51e97ce0b495dec05b..2759bc66fa221fad2088f84fecf449e52e374893 100644
--- a/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php
+++ b/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php
@@ -1035,10 +1035,9 @@ protected function assertNormalizationEdgeCases($method, Url $url, array $reques
         $request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
 
 
-        // DX: 400 when incorrect entity type bundle is specified.
-        // @todo Change to 422 in https://www.drupal.org/node/2827084.
+        // DX: 422 when incorrect entity type bundle is specified.
         $response = $this->request($method, $url, $request_options);
-        $this->assertResourceErrorResponse(400, '"bad_bundle_name" is not a valid bundle type for denormalization.', $response);
+        $this->assertResourceErrorResponse(422, '"bad_bundle_name" is not a valid bundle type for denormalization.', $response);
       }
 
 
@@ -1046,10 +1045,9 @@ protected function assertNormalizationEdgeCases($method, Url $url, array $reques
       $request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
 
 
-      // DX: 400 when no entity type bundle is specified.
-      // @todo Change to 422 in https://www.drupal.org/node/2827084.
+      // DX: 422 when no entity type bundle is specified.
       $response = $this->request($method, $url, $request_options);
-      $this->assertResourceErrorResponse(400, sprintf('Could not determine entity type bundle: "%s" field is missing.', $bundle_field_name), $response);
+      $this->assertResourceErrorResponse(422, sprintf('Could not determine entity type bundle: "%s" field is missing.', $bundle_field_name), $response);
     }
   }