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..30e1265
--- /dev/null
+++ b/core/modules/rest/src/Plugin/rest/resource/UserRegistrationResource.php
@@ -0,0 +1,199 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\rest\Plugin\rest\resource\UserRegistrationResource.
+ */
+
+namespace Drupal\rest\Plugin\rest\resource;
+
+use Drupal\Component\Utility\SafeMarkup;
+use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Entity\ContentEntityBase;
+use Drupal\rest\ResourceResponse;
+use Drupal\user\Entity\User;
+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\Core\Entity\Entity",
+ *   serialization_context = {
+ *     "entity_type" = "user"
+ *   }
+ * )
+ *
+ * @see \Drupal\rest\Plugin\Derivative\EntityDerivative
+ */
+class UserRegistrationResource extends ResourceBase {
+
+  /**
+   * The config factory.
+   *
+   * @var \Drupal\Core\Config\ConfigFactoryInterface
+   */
+  protected $configFactory;
+
+  /**
+   * 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 $loggery
+   *   A logger instance.
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
+   *   The config factory.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, array $serializer_formats, LoggerInterface $loggery, ConfigFactoryInterface $config_factory) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition, $serializer_formats, $loggery);
+    $this->configFactory = $config_factory;
+  }
+
+  /**
+   * {@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')
+    );
+  }
+
+  /**
+   * Responds to entity POST requests and saves the new entity.
+   *
+   * @param \Drupal\user\Entity\User $account
+   *   The user account entity.
+   *
+   * @return \Drupal\rest\ResourceResponse
+   *   The HTTP response object.
+   *
+   * @throws \Symfony\Component\HttpKernel\Exception\HttpException
+   */
+  public function post(User $account = NULL) {
+    if ($account == NULL) {
+      throw new BadRequestHttpException('No user account data for registration received.');
+    }
+
+    // Verify that the deserialized entity is of the type that we expect to
+    // prevent security issues.
+    if ($account->getEntityTypeId() != 'user') {
+      throw new BadRequestHttpException('Invalid entity type.');
+    }
+    // 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 created.');
+    }
+
+    $approvalSettings = $this->configFactory->get('user.settings')->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();
+    }
+
+    // Make sure that the user entity is valid (email and name are valid).
+    $this->validate($account);
+
+    // Cannot add extra roles.
+    $roles = $account->getRoles();
+    foreach ($roles as $role) {
+      if ($role != 'authenticated' && $role != 'anonymous') {
+        throw new BadRequestHttpException(SafeMarkup::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)));
+      }
+    }
+
+    $account->save();
+
+    // "Verify email" option disabled and the account as active means that the user can be logged in now.
+    if (!$this->configFactory->get('user.settings')->get('verify_mail') && $account->isActive()) {
+      _user_mail_notify('register_no_approval_required', $account);
+      user_login_finalize($account);
+    }
+    // The new account as blocked means that it needs approval.
+    elseif (!$account->isActive()) {
+      _user_mail_notify('register_pending_approval', $account);
+    }
+
+    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->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("$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\ContentEntityBase $entity
+   *   The entity object.
+   *
+   * @throws \Symfony\Component\HttpKernel\Exception\HttpException
+   *   If validation errors are found.
+   */
+  protected function validate(ContentEntityBase $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 2aa65ad..c132bb2 100644
--- a/core/modules/rest/src/RequestHandler.php
+++ b/core/modules/rest/src/RequestHandler.php
@@ -60,8 +60,17 @@ 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();
+        // 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();
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..844b845
--- /dev/null
+++ b/core/modules/rest/tests/src/Unit/UserRegistrationResourceTest.php
@@ -0,0 +1,199 @@
+<?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 the REST export view plugin.
+ *
+ * @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 $configStub;
+  protected $logger;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->configStub = $this->getConfigFactoryStub(array(
+      'user.settings' => array(
+        'register' => USER_REGISTER_VISITORS,
+        'verify_mail' => FALSE
+      ),
+    ));
+    $this->logger = $this->getMock('Psr\Log\LoggerInterface');
+    $this->testClass = new UserRegistrationResource([], 'plugin_id', '', [], $this->logger, $this->configStub);
+    $this->reflection = new \ReflectionClass($this->testClass);
+  }
+
+  public function getProtectedMethod($method) {
+    $method = $this->reflection->getMethod($method);
+    $method->setAccessible(TRUE);
+
+    return $method;
+  }
+
+  public function testValidate() {
+    $entity = $this->getMockBuilder('Drupal\user\Entity\User')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $entity->expects($this->once())
+      ->method('validate')
+      ->will($this->returnValue(array()));
+
+    $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();
+    $entity->expects($this->once())
+      ->method('validate')
+      ->will($this->returnValue(array($violation1, $violation2)));
+
+    $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 Invalid entity type.
+   */
+  public function testInvalidEntityTypePost() {
+    $entity = $this->getMockBuilder('Drupal\user\Entity\User')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $entity->expects($this->once())
+      ->method('getEntityTypeId')
+      ->will($this->returnValue('node'));
+    $this->testClass->post($entity);
+  }
+
+  /**
+   * @expectedException \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
+   * @expectedExceptionMessage Only new user accounts can be created.
+   */
+  public function testExistedEntityPost() {
+    $entity = $this->getMockBuilder('Drupal\user\Entity\User')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $entity->expects($this->once())
+      ->method('getEntityTypeId')
+      ->will($this->returnValue('user'));
+    $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->configStub = $this->getConfigFactoryStub(array(
+      'user.settings' => array(
+        'register' => USER_REGISTER_ADMINISTRATORS_ONLY,
+        'verify_mail' => FALSE
+      ),
+    ));
+    $this->testClass = new UserRegistrationResource([], 'plugin_id', '', [], $this->logger, $this->configStub);
+    $entity = $this->getMockBuilder('Drupal\user\Entity\User')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $entity->expects($this->once())
+      ->method('getEntityTypeId')
+      ->will($this->returnValue('user'));
+    $entity->expects($this->once())
+      ->method('isNew')
+      ->will($this->returnValue(TRUE));
+    $this->testClass->post($entity);
+  }
+
+  /**
+   * @expectedException \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
+   */
+  public function testInvalidRolesPost() {
+    $this->configStub = $this->getConfigFactoryStub(array(
+      'user.settings' => array(
+        'register' => USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL,
+        'verify_mail' => FALSE
+      ),
+    ));
+    $this->testClass = new UserRegistrationResource([], 'plugin_id', '', [], $this->logger, $this->configStub);
+    $entity = $this->getMockBuilder('Drupal\user\Entity\User')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $entity->expects($this->once())
+      ->method('getEntityTypeId')
+      ->will($this->returnValue('user'));
+    $entity->expects($this->once())
+      ->method('isNew')
+      ->will($this->returnValue(TRUE));
+    $entity->expects($this->once())
+      ->method('getRoles')
+      ->will($this->returnValue(array('administrator')));
+    $this->testClass->post($entity);
+  }
+
+}
