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..c748a0a
--- /dev/null
+++ b/core/modules/rest/src/Plugin/rest/resource/UserRegistrationResource.php
@@ -0,0 +1,225 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\rest\Plugin\rest\resource\UserRegistrationResource.
+ */
+
+namespace Drupal\rest\Plugin\rest\resource;
+
+use Drupal\Core\Config\Config;
+use Drupal\Core\Render\RenderContext;
+use Drupal\Core\Render\RendererInterface;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\rest\ResourceResponse;
+use Drupal\user\UserInterface;
+use Psr\Log\LoggerInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\Routing\RouteCollection;
+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\user\Entity\User"
+ * )
+ */
+class UserRegistrationResource extends ResourceBase {
+
+  /**
+   * User settings config instance.
+   *
+   * @var \Drupal\Core\Config\Config
+   */
+  protected $userSettings;
+
+  /**
+   * Current user object.
+   *
+   * @var \Drupal\Core\Session\AccountInterface
+   */
+  protected $currentUser;
+
+  /**
+   * The renderer.
+   *
+   * @var \Drupal\Core\Render\RendererInterface
+   */
+  protected $renderer;
+
+  /**
+   * Constructs a new RestPermissions instance.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param mixed $plugin_definition
+   *   The plugin implementation definition.
+   * @param array $serializer_formats
+   *   The available serialization formats.
+   * @param LoggerInterface $logger
+   *   A logger instance.
+   * @param \Drupal\Core\Config\Config $user_settings
+   *   A user settings config instance.
+   * @param \Drupal\Core\Session\AccountInterface $current_user
+   *   A user settings config instance.
+   * @param \Drupal\Core\Render\RendererInterface $renderer
+   *   The renderer.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, array $serializer_formats, LoggerInterface $logger, Config $user_settings, AccountInterface $current_user, RendererInterface $renderer) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition, $serializer_formats, $logger);
+    $this->userSettings = $user_settings;
+    $this->currentUser = $current_user;
+    $this->renderer = $renderer;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->getParameter('serializer.formats'),
+      $container->get('logger.factory')->get('rest'),
+      $container->get('config.factory')->get('user.settings'),
+      $container->get('current_user'),
+      $container->get('renderer')
+    );
+  }
+
+  /**
+   * Responds to user registration POST request.
+   *
+   * @param \Drupal\user\UserInterface $account
+   *   The user account entity.
+   *
+   * @return \Drupal\rest\ResourceResponse
+   *   The HTTP response object.
+   *
+   * @throws \Symfony\Component\HttpKernel\Exception\HttpException
+   */
+  public function post(UserInterface $account = NULL) {
+    if ($account == NULL) {
+      throw new BadRequestHttpException('No user account data for registration received.');
+    }
+
+    // POSTed user accounts must not have an ID set, because we always
+    // want to create new entities here.
+    if (!$account->isNew()) {
+      throw new BadRequestHttpException('Only new user accounts can be registered.');
+    }
+
+    // The current resource only allows anonymous users to register users.
+    if (!$this->currentUser->isAnonymous()) {
+      throw new AccessDeniedHttpException('Only anonymous users can register users.');
+    }
+    $approvalSettings = $this->userSettings->get('register');
+    // Verify that the current user can register a user account.
+    if ($approvalSettings == USER_REGISTER_ADMINISTRATORS_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 == USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL) {
+      $account->block();
+    }
+
+    // Only check 'edit' permissions for fields that were actually
+    // submitted by the user. Field access makes no difference between 'create'
+    // and 'update', so the 'edit' operation is used here.
+    foreach ($account->_restSubmittedFields as $key => $field_name) {
+      if (!$account->get($field_name)->access('edit')) {
+        throw new AccessDeniedHttpException("Access denied on creating field '$field_name'.");
+      }
+    }
+
+    // Make sure that the user entity is valid (email and name are valid).
+    $this->validate($account);
+
+    $account->save();
+    // Send emails from a render context to add bubbleable_metadata to the
+    // response.
+    $context = new RenderContext();
+    $this->renderer->executeInRenderContext($context, function() use ($account) {
+      $register = $this->userSettings->get('register');
+      // No email verification is required. Activating the user.
+      if ($register == 'visitors') {
+        if (!$this->userSettings->get('verify_mail')) {
+          // Notification will be sent if activated.
+          $account->activate();
+          $account->save();
+        }
+        // No administrator approval required.
+        else {
+          _user_mail_notify('register_no_approval_required', $account);
+        }
+      }
+      // Administrator approval required.
+      elseif ($register == 'visitors_admin_approval') {
+        _user_mail_notify('register_pending_approval', $account);
+      }
+    });
+
+    $response = new ResourceResponse(NULL, 201, ['Location' => 'user/' . $account->id()]);
+    if (!$context->isEmpty()) {
+      $response->addCacheableDependency($context->pop());
+    }
+
+    return $response;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function routes() {
+    $collection = new RouteCollection();
+
+    $route = $this->getBaseRoute('/entity/user/register', 'POST');
+    $route->setPath('/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("$this->pluginId", $route);
+
+    return $collection;
+  }
+
+  /**
+   * Verifies that the whole entity does not violate any validation constraints.
+   *
+   * @param \Drupal\user\UserInterface $entity
+   *   The entity object.
+   *
+   * @throws \Symfony\Component\HttpKernel\Exception\HttpException
+   *   If validation errors are found.
+   */
+  protected function validate(UserInterface $entity) {
+    $violations = $entity->validate();
+
+    // Remove violations of inaccessible fields as they cannot stem from our
+    // changes.
+    $violations->filterByFieldAccess();
+
+    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 ee4b890..60f8695 100644
--- a/core/modules/rest/src/RequestHandler.php
+++ b/core/modules/rest/src/RequestHandler.php
@@ -61,8 +61,11 @@ public function handle(RouteMatchInterface $route_match, Request $request) {
       if (empty($method_settings['supported_formats']) || in_array($format, $method_settings['supported_formats'])) {
         $definition = $resource->getPluginDefinition();
         $class = $definition['serialization_class'];
+        $context = array();
+        $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();
diff --git a/core/modules/rest/src/Tests/RegisterUserTest.php b/core/modules/rest/src/Tests/RegisterUserTest.php
new file mode 100644
index 0000000..ca3edc8
--- /dev/null
+++ b/core/modules/rest/src/Tests/RegisterUserTest.php
@@ -0,0 +1,109 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\rest\Tests\RegisterUserTest.
+ */
+
+namespace Drupal\rest\Tests;
+use Drupal\user\Entity\Role;
+use Drupal\user\RoleInterface;
+
+
+/**
+ * Tests User Registration.
+ *
+ * @group rest
+ */
+class RegisterUserTest extends RESTTestBase {
+
+  /**
+   * Modules to install.
+   *
+   * @var array
+   */
+  public static $modules = ['hal'];
+
+  /**
+   * Enables user registration specific REST API configuration and authenticate.
+   */
+  protected function enableUserRegistrationConfiguration() {
+    // Enabling services for the user registration and GET the new user entity
+    // created.
+    $config = $this->config('rest.settings');
+    $settings = [];
+    $resources = [
+      ['type' => 'rest_user_registration', 'method' => 'POST'],
+      ['type' => 'entity:user', 'method' => 'GET']
+    ];
+    $format = 'hal_json';
+    $auth = $this->defaultAuth;
+    foreach ($resources as $resource) {
+      $settings[$resource['type']][$resource['method']]['supported_formats'][] = $format;
+      $settings[$resource['type']][$resource['method']]['supported_auth'] = $auth;
+      $config->set('resources', $settings);
+      $config->save();
+    }
+    $this->rebuildCache();
+
+    // Add registration permission to anonymous user.
+    Role::load(RoleInterface::ANONYMOUS_ID)
+      ->grantPermission('restful post rest_user_registration')
+      ->save();
+
+  }
+
+  /**
+   * Tests user registration from REST.
+   */
+  protected function testRegisterUser() {
+
+    $this->enableUserRegistrationConfiguration();
+    // New user info to be serialized.
+    $data = [
+      "_links" =>
+        [
+          "type" => ["href" => $GLOBALS['base_url'] . "/rest/type/user/user"]
+        ],
+      "langcode" =>  [
+        [
+          "value" => "en"
+        ]
+      ],
+      "name" => [
+        [
+          "value" => "Druplicon"
+        ]
+      ],
+      "mail" => [
+        [
+          "value" => "druplicon@superpoweredbydrupal.com"
+        ]
+      ],
+      "pass" => [
+        [
+          "value" => "SuperSecretPassword"
+        ]
+      ]
+    ];
+
+    // Create a JSON version for the user entity we want to create.
+    $serialized = \Drupal::service('serializer')->serialize($data, 'hal_json');
+
+    // Post to the REST service to register the user.
+    $this->httpRequest('entity/user/register', 'POST', $serialized, 'application/hal+json');
+    $this->assertResponse('201', 'HTTP response code is correct.');
+
+    // Obtain the uid from the header.
+    $url_parts = explode('/', $this->drupalGetHeader('location'));
+    $id = end($url_parts);
+    $this->assertHeader('Location', 'user/' . $id);
+
+    $this->assertTrue((bool) \Drupal::entityQuery('user')
+      ->condition('name', 'Druplicon')
+      ->range(0, 1)
+      ->count()
+      ->execute(), 'The user was created as expected');
+  }
+
+}
diff --git a/core/modules/rest/tests/src/Unit/UserRegistrationResourceTest.php b/core/modules/rest/tests/src/Unit/UserRegistrationResourceTest.php
new file mode 100644
index 0000000..18f95f7
--- /dev/null
+++ b/core/modules/rest/tests/src/Unit/UserRegistrationResourceTest.php
@@ -0,0 +1,250 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\rest\Unit\UserRegistrationResourceTest.
+ */
+
+namespace Drupal\Tests\rest\Unit;
+
+use Drupal\rest\Plugin\rest\resource\UserRegistrationResource;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * Only administrators can create user accounts.
+ */
+define('USER_REGISTER_ADMINISTRATORS_ONLY', 'admin_only');
+
+/**
+ * Visitors can create their own accounts.
+ */
+define('USER_REGISTER_VISITORS', 'visitors');
+
+/**
+ * Visitors can create accounts, but they don't become active without
+ * administrative approval.
+ */
+define('USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL', 'visitors_admin_approval');
+
+
+/**
+ * Tests User Registration REST resource.
+ *
+ * @group rest
+ */
+class UserRegistrationResourceTest extends UnitTestCase {
+
+  const ERROR_MESSAGE = "Unprocessable Entity: validation failed.\nproperty_path: message\nproperty_path_2: message_2\n";
+
+  protected $testClass;
+  protected $reflection;
+  protected $userSettings;
+  protected $logger;
+  protected $currentUser;
+  protected $renderer;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->logger = $this->getMock('Psr\Log\LoggerInterface');
+    $this->userSettings = $this->getMockBuilder('Drupal\Core\Config\Config')
+      ->setMethods(['get'])
+      ->disableOriginalConstructor()
+      ->getMock();
+
+    $this->currentUser = $this->getMockBuilder('Drupal\Core\Session\AccountInterface')
+      ->disableOriginalConstructor()
+      ->getMock();
+
+    $this->renderer = $this->getMockBuilder('Drupal\Core\Render\RendererInterface')
+      ->disableOriginalConstructor()
+      ->getMock();
+
+    $this->testClass = new UserRegistrationResource([], 'plugin_id', '', [], $this->logger, $this->userSettings, $this->currentUser, $this->renderer);
+    $this->reflection = new \ReflectionClass($this->testClass);
+
+  }
+
+  public function getProtectedMethod($method) {
+    $method = $this->reflection->getMethod($method);
+    $method->setAccessible(TRUE);
+
+    return $method;
+  }
+
+  public function testValidate() {
+
+    $violations = $this->getMockBuilder('Drupal\Core\Entity\EntityConstraintViolationList')
+      ->setMethods(['filterByFieldAccess'])
+      ->disableOriginalConstructor()
+      ->getMock();
+
+    $violations->expects($this->once())
+      ->method('filterByFieldAccess')
+      ->will($this->returnValue(array()));
+
+    $entity = $this->getMockBuilder('Drupal\user\Entity\User')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $entity->expects($this->once())
+      ->method('validate')
+      ->will($this->returnValue($violations));
+
+    $method = $this->getProtectedMethod('validate');
+    // No exception is thrown.
+    $method->invokeArgs($this->testClass, array($entity));
+  }
+
+  /**
+   * @expectedException \Symfony\Component\HttpKernel\Exception\HttpException
+   * @expectedException UserRegistrationResourceTest::ERROR_MESSAGE
+   */
+  public function testFailedValidate() {
+    $violation1 = $this->getMock('Symfony\Component\Validator\ConstraintViolationInterface');
+    $violation1->expects($this->once())
+      ->method('getPropertyPath')
+      ->will($this->returnValue('property_path'));
+    $violation1->expects($this->once())
+      ->method('getMessage')
+      ->will($this->returnValue('message'));
+    $violation2 = $this->getMock('Symfony\Component\Validator\ConstraintViolationInterface');
+    $violation2->expects($this->once())
+      ->method('getPropertyPath')
+      ->will($this->returnValue('property_path_2'));
+    $violation2->expects($this->once())
+      ->method('getMessage')
+      ->will($this->returnValue('message_2'));
+    $entity = $this->getMockBuilder('Drupal\user\Entity\User')
+      ->disableOriginalConstructor()
+      ->getMock();
+
+    $violations = $this->getMockBuilder('Drupal\Core\Entity\EntityConstraintViolationList')
+      ->setConstructorArgs([$entity, [$violation1, $violation2]])
+      ->setMethods(['filterByFieldAccess'])
+      ->getMock();
+
+    $violations->expects($this->once())
+      ->method('filterByFieldAccess')
+      ->will($this->returnValue([]));
+
+    $entity->expects($this->once())
+      ->method('validate')
+      ->will($this->returnValue($violations));
+
+    $method = $this->getProtectedMethod('validate');
+    // No exception is thrown.
+    $method->invoke($this->testClass, $entity);
+  }
+
+  /**
+   * @expectedException \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
+   * @expectedExceptionMessage No user account data for registration received.
+   */
+  public function testEmptyPost() {
+    $this->testClass->post(NULL);
+  }
+
+  /**
+   * @expectedException \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
+   * @expectedExceptionMessage Only new user accounts can be registered.
+   */
+  public function testExistedEntityPost() {
+    $entity = $this->getMockBuilder('Drupal\user\Entity\User')
+      ->disableOriginalConstructor()
+      ->getMock();
+
+    $entity->expects($this->once())
+      ->method('isNew')
+      ->will($this->returnValue(FALSE));
+
+    $this->testClass->post($entity);
+  }
+
+  /**
+   * @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
+   * @expectedExceptionMessage Only administrators can register users.
+   */
+  public function testRegistrationAdminOnlyPost() {
+    $this->currentUser->expects($this->once())
+      ->method('isAnonymous')
+      ->will($this->returnValue(TRUE));
+
+    $this->userSettings->expects($this->once())
+      ->method('get')
+      ->will($this->returnValue(USER_REGISTER_ADMINISTRATORS_ONLY));
+
+    $this->testClass = new UserRegistrationResource([], 'plugin_id', '', [], $this->logger, $this->userSettings, $this->currentUser, $this->renderer);
+    $entity = $this->getMockBuilder('Drupal\user\Entity\User')
+      ->disableOriginalConstructor()
+      ->getMock();
+
+    $entity->expects($this->once())
+      ->method('isNew')
+      ->will($this->returnValue(TRUE));
+
+    $this->testClass->post($entity);
+  }
+
+  /**
+   * @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
+   * @expectedExceptionMessage Only anonymous users can register users.
+   */
+  public function testRegistrationAnonymousOnlyPost() {
+    $this->currentUser->expects($this->once())
+      ->method('isAnonymous')
+      ->will($this->returnValue(FALSE));
+
+    $this->testClass = new UserRegistrationResource([], 'plugin_id', '', [], $this->logger, $this->userSettings, $this->currentUser, $this->renderer);
+    $entity = $this->getMockBuilder('Drupal\user\Entity\User')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $entity->expects($this->once())
+      ->method('isNew')
+      ->will($this->returnValue(TRUE));
+
+    $this->testClass->post($entity);
+  }
+
+  /**
+   * @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
+   * @expectedExceptionMessage Access denied on creating field 'test_field'.
+   */
+  public function testFieldAccessValidation() {
+    $this->currentUser->expects($this->once())
+      ->method('isAnonymous')
+      ->will($this->returnValue(TRUE));
+
+    $this->testClass = new UserRegistrationResource([], 'plugin_id', '', [], $this->logger, $this->userSettings, $this->currentUser, $this->renderer);
+    $entity = $this->getMockBuilder('Drupal\user\Entity\User')
+      ->disableOriginalConstructor()
+      ->getMock();
+
+
+    $entity->expects($this->once())
+      ->method('isNew')
+      ->will($this->returnValue(TRUE));
+
+    $field = $this->getMockBuilder('\Drupal\Core\Field\FieldItemList')
+      ->setMethods(['access'])
+      ->disableOriginalConstructor()
+      ->getMock();
+
+    $field->expects($this->once())
+      ->method('access')
+      ->will($this->returnValue(FALSE));
+
+    $entity->expects($this->once())
+      ->method('get')
+      ->will($this->returnValue($field));
+
+    $entity->expects($this->once())
+      ->method('__get')
+      ->will($this->returnValue(['test' => 'test_field']));
+
+    $this->testClass->post($entity);
+  }
+
+}
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index a19acc6..db60300 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -1206,7 +1206,7 @@ function user_role_revoke_permissions($rid, array $permissions = array()) {
  *   language.
  *
  * @return array
- *   An array containint various information about the message.
+ *   An array containing various information about the message.
  *   See \Drupal\Core\Mail\MailManagerInterface::mail() for details.
  *
  * @see user_mail_tokens()
