diff --git a/core/modules/rest/src/Annotation/RestResource.php b/core/modules/rest/src/Annotation/RestResource.php
index e63f07d..947e3dd 100644
--- a/core/modules/rest/src/Annotation/RestResource.php
+++ b/core/modules/rest/src/Annotation/RestResource.php
@@ -43,4 +43,11 @@ class RestResource extends Plugin {
    */
   public $label;
 
+  /**
+   * Options available.
+   *
+   * @var array
+   */
+  public $serialization_context;
+
 }
diff --git a/core/modules/rest/src/Plugin/rest/resource/UserRegistrationResource.php b/core/modules/rest/src/Plugin/rest/resource/UserRegistrationResource.php
new file mode 100644
index 0000000..f384346
--- /dev/null
+++ b/core/modules/rest/src/Plugin/rest/resource/UserRegistrationResource.php
@@ -0,0 +1,156 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\rest\Plugin\rest\resource\UserRegistrationResource.
+ */
+
+namespace Drupal\rest\Plugin\rest\resource;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\rest\ResourceResponse;
+use Symfony\Component\Routing\RouteCollection;
+use Drupal\Component\Utility\String;
+use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
+use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
+use Drupal\rest\Plugin\ResourceBase;
+use Symfony\Component\HttpKernel\Exception\HttpException;
+
+/**
+ * Represents user registration as resource.
+ *
+ * @RestResource(
+ *   id = "rest_user_registration",
+ *   label = @Translation("User Registration"),
+ *   serialization_class = "Drupal\Core\Entity\Entity",
+ *   serialization_context = {
+ *     "entity_type" = "user"
+ *   }
+ * )
+ *
+ * @see \Drupal\rest\Plugin\Derivative\EntityDerivative
+ */
+class UserRegistrationResource extends ResourceBase {
+
+  /**
+   * Responds to entity POST requests and saves the new entity.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity.
+   *
+   * @return \Drupal\rest\ResourceResponse
+   *   The HTTP response object.
+   *
+   * @throws \Symfony\Component\HttpKernel\Exception\HttpException
+   */
+  public function post(EntityInterface $entity = NULL) {
+
+    if ($entity == NULL) {
+      throw new BadRequestHttpException('No entity content received.');
+    }
+
+    $definition = $this->getPluginDefinition();
+    // Verify that the deserialized entity is of the type that we expect to
+    // prevent security issues.
+    if ($entity->getEntityTypeId() != $definition['serialization_context']['entity_type']) {
+      throw new BadRequestHttpException('Invalid entity type');
+    }
+    // POSTed entities must not have an ID set, because we always want to create
+    // new entities here.
+    if (!$entity->isNew()) {
+      throw new BadRequestHttpException('Only new entities can be created');
+    }
+
+    $approvalSettings = \Drupal::config('user.settings')->get('register');
+    // Verify that the current user can register a user account.
+    if ($approvalSettings == 'admin_only') {
+      throw new AccessDeniedHttpException('Only administrators can register users.');
+    }
+    // If current user can register accounts then let's block the new registered user if admin approval is needed.
+    elseif ($approvalSettings == 'visitors_admin_approval') {
+      $entity->block();
+    }
+
+    // Username and email cannot exist.
+    $this->validate($entity);
+
+    // Cannot add extra roles.
+    $roles = $entity->getRoles();
+    foreach ($roles as $role) {
+      if ($role != 'authenticated' && $role != 'anonymous') {
+        throw new BadRequestHttpException(String::format('Anonymous user cannot assign roles when registering a new user account and by default' .
+          ' authenticated is added, so you cannot assign @role role.', array('@role' => $role)));
+      }
+    }
+
+    $entity->save();
+
+    // "Verify email" option disabled and the account as active means that the user can be logged in now.
+    if (!\Drupal::config('user.settings')->get('verify_mail') && $entity->isActive()) {
+      _user_mail_notify('register_no_approval_required', $entity);
+      user_login_finalize($entity);
+    }
+    // The new account as blocked means that it needs approval.
+    elseif (!$entity->isActive()) {
+      _user_mail_notify('register_pending_approval', $entity);
+    }
+
+    return new ResourceResponse(NULL, 201);
+
+  }
+
+  /**
+   * Implements ResourceInterface::routes().
+   */
+  public function routes() {
+    $collection = new RouteCollection();
+
+    $route_name = strtr($this->pluginId, ':', '.');
+
+    $methods = $this->availableMethods();
+    foreach ($methods as $method) {
+      $route = $this->getBaseRoute('/entity/user/register', $method);
+
+      switch ($method) {
+        case 'POST':
+          $route->setPattern('/entity/user/register');
+          // Restrict the incoming HTTP Content-type header to the known
+          // serialization formats.
+          $route->addRequirements(array('_content_type_format' => implode('|', $this->serializerFormats)));
+          $collection->add("$route_name.$method", $route);
+          break;
+
+        default:
+          $collection->add("$route_name.$method", $route);
+          break;
+      }
+    }
+
+    return $collection;
+  }
+
+  /**
+   * Verifies that the whole entity does not violate any validation constraints.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity object.
+   *
+   * @throws \Symfony\Component\HttpKernel\Exception\HttpException
+   *   If validation errors are found.
+   */
+  protected function validate(EntityInterface $entity) {
+    $violations = $entity->validate();
+    if (count($violations) > 0) {
+      $message = "Unprocessable Entity: validation failed.\n";
+      foreach ($violations as $violation) {
+        $message .= $violation->getPropertyPath() . ': ' . $violation->getMessage() . "\n";
+      }
+      // Instead of returning a generic 400 response we use the more specific
+      // 422 Unprocessable Entity code from RFC 4918. That way clients can
+      // distinguish between general syntax errors in bad serializations (code
+      // 400) and semantic errors in well-formed requests (code 422).
+      throw new HttpException(422, $message);
+    }
+  }
+
+}
diff --git a/core/modules/rest/src/RequestHandler.php b/core/modules/rest/src/RequestHandler.php
index 0ddfdd7..1071ddc 100644
--- a/core/modules/rest/src/RequestHandler.php
+++ b/core/modules/rest/src/RequestHandler.php
@@ -62,8 +62,17 @@ public function handle(RouteMatchInterface $route_match, Request $request, Route
       if (empty($method_settings['supported_formats']) || in_array($format, $method_settings['supported_formats'])) {
         $definition = $resource->getPluginDefinition();
         $class = $definition['serialization_class'];
+        $context = array();
+        // Get context information for deserialization from the plugin
+        // definition.
+        if (!empty($definition['serialization_context'])) {
+          $context = $definition['serialization_context'];
+        }
+        // Always add the resource ID to the deserialization context.
+        $context['resource_id'] = $plugin;
+        $context['request_method'] = $method;
         try {
-          $unserialized = $serializer->deserialize($received, $class, $format, array('request_method' => $method));
+          $unserialized = $serializer->deserialize($received, $class, $format, $context);
         }
         catch (UnexpectedValueException $e) {
           $error['error'] = $e->getMessage();
