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..51bb3d4
--- /dev/null
+++ b/core/modules/rest/src/Plugin/rest/resource/UserRegistrationResource.php
@@ -0,0 +1,206 @@
+<?php
+
+namespace Drupal\rest\Plugin\rest\resource;
+
+use Drupal\Core\Config\ImmutableConfig;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\rest\ModifiedResourceResponse;
+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",
+ *   uri_paths = {
+ *     "https://www.drupal.org/link-relations/create" = "/user/register",
+ *   },
+ * )
+ */
+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;
+
+  /**
+   * Constructs a new UserRegistrationResource 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 \Psr\Log\LoggerInterface $logger
+   *   A logger instance.
+   * @param \Drupal\Core\Config\ImmutableConfig $user_settings
+   *   A user settings config instance.
+   * @param \Drupal\Core\Session\AccountInterface $current_user
+   *   A user settings config instance.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, array $serializer_formats, LoggerInterface $logger, ImmutableConfig $user_settings, AccountInterface $current_user) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition, $serializer_formats, $logger);
+    $this->userSettings = $user_settings;
+    $this->currentUser = $current_user;
+  }
+
+  /**
+   * {@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')
+    );
+  }
+
+  /**
+   * Responds to user registration POST request.
+   *
+   * @param \Drupal\user\UserInterface $account
+   *   The user account entity.
+   *
+   * @return \Drupal\rest\ModifiedResourceResponse
+   *   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('An ID has been set and 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);
+    // Create the account.
+    $account->save();
+
+    $register = $this->userSettings->get('register');
+    // No E-mail verification is required. Activating the user.
+    if ($register == 'visitors') {
+      if (!$this->userSettings->get('verify_mail')) {
+        // Notification will be sent if activated.
+        $account->activate();
+        // Save changes to apply active status to the account.
+        $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);
+    }
+
+    $url = $account->toUrl('canonical', ['absolute' => TRUE])->toString(TRUE);
+    $response = new ModifiedResourceResponse(NULL, 201, ['Location' => $url->getGeneratedUrl()]);
+
+    return $response;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function routes() {
+    $collection = new RouteCollection();
+
+    $route = $this->getBaseRoute('/user/register', 'POST');
+
+    // Restrict the incoming HTTP Content-type header to the known serialization
+    // formats.
+    $route->addRequirements(['_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 ($violations->count() > 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/Tests/RegisterUserTest.php b/core/modules/rest/src/Tests/RegisterUserTest.php
new file mode 100644
index 0000000..bda801c
--- /dev/null
+++ b/core/modules/rest/src/Tests/RegisterUserTest.php
@@ -0,0 +1,103 @@
+<?php
+
+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'];
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    parent::setUp();
+    // 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'],
+    ];
+    $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.
+   */
+  public function testRegisterUser() {
+
+    // 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@example.com"
+        ]
+      ],
+      "pass" => [
+        [
+          "value" => "SuperSecretPassword"
+        ]
+      ]
+    ];
+
+    // Create a JSON version for the user entity we want to create.
+    $serialized = $this->container->get('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', $GLOBALS['base_url'] . '/user/' . $id);
+
+    $this->assertTrue((bool) $this->container->get('entity.query')
+      ->get('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..93fdfa1
--- /dev/null
+++ b/core/modules/rest/tests/src/Unit/UserRegistrationResourceTest.php
@@ -0,0 +1,262 @@
+<?php
+
+namespace Drupal\Tests\rest\Unit;
+
+use Drupal\Core\Config\ImmutableConfig;
+use Drupal\Core\Field\FieldItemList;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\rest\Plugin\rest\resource\UserRegistrationResource;
+use Drupal\Tests\UnitTestCase;
+use Drupal\user\Entity\User;
+use Psr\Log\LoggerInterface;
+use Drupal\Core\Entity\EntityConstraintViolationList;
+use Symfony\Component\Validator\ConstraintViolationInterface;
+
+/**
+ * Only administrators can create user accounts.
+ */
+if (!defined('USER_REGISTER_ADMINISTRATORS_ONLY')) {
+  define('USER_REGISTER_ADMINISTRATORS_ONLY', 'admin_only');
+}
+
+/**
+ * Visitors can create their own accounts.
+ */
+if (!defined('USER_REGISTER_VISITORS')) {
+  define('USER_REGISTER_VISITORS', 'visitors');
+}
+
+/**
+ * Visitors can create accounts, but they don't become active without
+ * administrative approval.
+ */
+if (!defined('USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL')) {
+  define('USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL', 'visitors_admin_approval');
+}
+
+/**
+ * Tests User Registration REST resource.
+ *
+ * @coversDefaultClass \Drupal\Tests\rest\Unit\UserRegistrationResourceTest
+ * @group rest
+ */
+class UserRegistrationResourceTest extends UnitTestCase {
+
+  const ERROR_MESSAGE = "Unprocessable Entity: validation failed.\nproperty_path: message\nproperty_path_2: message_2\n";
+
+  /**
+   * Class to be tested.
+   *
+   * @var \Drupal\rest\Plugin\rest\resource\UserRegistrationResource
+   */
+  protected $testClass;
+
+  /**
+   * A reflection of self::$testClass.
+   *
+   * @var \ReflectionClass
+   */
+  protected $reflection;
+
+  /**
+   * A user settings config instance.
+   *
+   * @var \Drupal\Core\Config\ImmutableConfig|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $userSettings;
+
+  /**
+   * Logger service.
+   *
+   * @var \Psr\Log\LoggerInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $logger;
+
+  /**
+   * The current user.
+   *
+   * @var \Drupal\Core\Session\AccountInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $currentUser;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->logger = $this->prophesize(LoggerInterface::class)->reveal();
+
+    $this->userSettings = $this->prophesize(ImmutableConfig::class);
+
+    $this->currentUser = $this->prophesize(AccountInterface::class);
+
+    $this->testClass = new UserRegistrationResource([], 'plugin_id', '', [], $this->logger, $this->userSettings->reveal(), $this->currentUser->reveal());
+    $this->reflection = new \ReflectionClass($this->testClass);
+  }
+
+  /**
+   * Helper method to set a protected method as accessible.
+   *
+   * @param string $method
+   *   The protected method.
+   *
+   * @return \ReflectionMethod
+   */
+  public function getProtectedMethod($method) {
+    $method = $this->reflection->getMethod($method);
+    $method->setAccessible(TRUE);
+
+    return $method;
+  }
+
+  /**
+   * Tests that the user entity does not violate any validation constraints.
+   */
+  public function testValidate() {
+    $violations = $this->prophesize(EntityConstraintViolationList::class);
+    $violations->filterByFieldAccess()->willReturn([]);
+    $violations->count()->willReturn(0);
+
+    $entity = $this->prophesize(User::class);
+    $entity->validate()->willReturn($violations->reveal());
+
+    $method = $this->getProtectedMethod('validate');
+
+    // No exception is thrown.
+    $method->invokeArgs($this->testClass, [$entity->reveal()]);
+  }
+
+  /**
+   * Tests that error validation is thrown as expected.
+   *
+   * @expectedException \Symfony\Component\HttpKernel\Exception\HttpException
+   * @expectedException UserRegistrationResourceTest::ERROR_MESSAGE
+   */
+  public function testFailedValidate() {
+    $violation1 = $this->prophesize(ConstraintViolationInterface::class);
+    $violation1->getPropertyPath()->willReturn('property_path');
+    $violation1->getMessage()->willReturn('message');
+
+    $violation2 = $this->prophesize(ConstraintViolationInterface::class);
+    $violation2->getPropertyPath()->willReturn('property_path');
+    $violation2->getMessage()->willReturn('message');
+
+    $entity = $this->prophesize(User::class);
+
+    $violations = $this->getMockBuilder(EntityConstraintViolationList::class)
+      ->setConstructorArgs([$entity->reveal(), [$violation1->reveal(), $violation2->reveal()]])
+      ->setMethods(['filterByFieldAccess'])
+      ->getMock();
+
+    $violations->expects($this->once())
+      ->method('filterByFieldAccess')
+      ->will($this->returnValue([]));
+
+    $entity->validate()->willReturn($violations);
+
+    $method = $this->getProtectedMethod('validate');
+
+    $method->invoke($this->testClass, $entity->reveal());
+  }
+
+  /**
+   * Tests that an exception is thrown when no data provided for the account.
+   *
+   * @expectedException \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
+   * @expectedExceptionMessage No user account data for registration received.
+   */
+  public function testEmptyPost() {
+    $this->testClass->post(NULL);
+  }
+
+  /**
+   * Tests that only new user accounts can be registered.
+   *
+   * @expectedException \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
+   * @expectedExceptionMessage An ID has been set and only new user accounts can be registered.
+   */
+  public function testExistedEntityPost() {
+    $entity = $this->prophesize(User::class);
+    $entity->isNew()->willReturn(FALSE);
+
+    $this->testClass->post($entity->reveal());
+  }
+
+  /**
+   * Tests that admin permissions are required to register a user account.
+   *
+   * @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
+   * @expectedExceptionMessage Only administrators can register users.
+   */
+  public function testRegistrationAdminOnlyPost() {
+
+    $this->userSettings->get('register')->willReturn(USER_REGISTER_ADMINISTRATORS_ONLY);
+
+    $this->currentUser->isAnonymous()->willReturn(TRUE);
+
+    $this->testClass = new UserRegistrationResource([], 'plugin_id', '', [], $this->logger, $this->userSettings->reveal(), $this->currentUser->reveal());
+
+    $entity = $this->prophesize(User::class);
+    $entity->isNew()->willReturn(TRUE);
+
+    $this->testClass->post($entity->reveal());
+  }
+
+  /**
+   * Tests that only anonymous users can register users.
+   *
+   * @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
+   * @expectedExceptionMessage Only anonymous users can register users.
+   */
+  public function testRegistrationAnonymousOnlyPost() {
+    $this->currentUser->isAnonymous()->willReturn(FALSE);
+
+    $this->testClass = new UserRegistrationResource([], 'plugin_id', '', [], $this->logger, $this->userSettings->reveal(), $this->currentUser->reveal());
+
+    $entity = $this->prophesize(User::class);
+    $entity->isNew()->willReturn(TRUE);
+
+    $this->testClass->post($entity->reveal());
+  }
+
+  /**
+   * Tests access denied on creating field.
+   *
+   * @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
+   * @expectedExceptionMessage Access denied on creating field 'test_field'.
+   */
+  public function testFieldAccessValidation() {
+    $this->currentUser->isAnonymous()->willReturn(TRUE);
+
+    $this->testClass = new UserRegistrationResource([], 'plugin_id', '', [], $this->logger, $this->userSettings->reveal(), $this->currentUser->reveal());
+
+    $entity = $this->getMockBuilder(User::class)
+      ->disableOriginalConstructor()
+      ->getMock();
+
+    $entity->expects($this->once())
+      ->method('isNew')
+      ->will($this->returnValue(TRUE));
+
+    $field = $this->getMockBuilder(FieldItemList::class)
+      ->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);
+  }
+
+}
