diff --git a/core/modules/rest/config/install/rest.settings.yml b/core/modules/rest/config/install/rest.settings.yml
index e2699fc..a3c8d25 100644
--- a/core/modules/rest/config/install/rest.settings.yml
+++ b/core/modules/rest/config/install/rest.settings.yml
@@ -25,6 +25,11 @@ resources:
         - hal_json
       supported_auth:
         - basic_auth
+    OPTIONS:
+      supported_formats:
+        - hal_json
+      supported_auth:
+        - basic_auth
 
 # Multiple formats and multiple authentication providers can be defined for a
 # resource:
diff --git a/core/modules/rest/rest.services.yml b/core/modules/rest/rest.services.yml
index c25d692..2c69173 100644
--- a/core/modules/rest/rest.services.yml
+++ b/core/modules/rest/rest.services.yml
@@ -30,3 +30,8 @@ services:
   logger.channel.rest:
     parent: logger.channel_base
     arguments: ['rest']
+  rest.options_subscriber:
+    class: Drupal\rest\Routing\OptionsRequestSubscriber
+    arguments: ['@access_manager', '@current_user']
+    tags:
+      - {name: event_subscriber}
diff --git a/core/modules/rest/src/Plugin/rest/resource/EntityResource.php b/core/modules/rest/src/Plugin/rest/resource/EntityResource.php
index b565cea..eead860 100644
--- a/core/modules/rest/src/Plugin/rest/resource/EntityResource.php
+++ b/core/modules/rest/src/Plugin/rest/resource/EntityResource.php
@@ -192,6 +192,21 @@ public function delete(EntityInterface $entity) {
   }
 
   /**
+   * Responds to entity OPTIONS requests.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity object.
+   *
+   * @return \Drupal\rest\ResourceResponse
+   *   The HTTP response object.
+   *
+   * @throws \Symfony\Component\HttpKernel\Exception\HttpException
+   */
+  public function options(EntityInterface $entity) {
+    return new ResourceResponse(NULL, 204);
+  }
+
+  /**
    * Verifies that the whole entity does not violate any validation constraints.
    *
    * @param \Drupal\Core\Entity\EntityInterface $entity
diff --git a/core/modules/rest/src/Routing/OptionsRequestSubscriber.php b/core/modules/rest/src/Routing/OptionsRequestSubscriber.php
new file mode 100644
index 0000000..8502763
--- /dev/null
+++ b/core/modules/rest/src/Routing/OptionsRequestSubscriber.php
@@ -0,0 +1,103 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\rest\Routing\OptionsRequestListener
+ */
+
+namespace Drupal\rest\Routing;
+
+use Drupal\Core\Access\AccessManager;
+use Drupal\Core\Session\AccountInterface;
+use Symfony\Cmf\Component\Routing\RouteObjectInterface;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\Event\GetResponseEvent;
+use Symfony\Component\HttpKernel\KernelEvents;
+
+/**
+ * Handles OPTIONS requests.
+ */
+class OptionsRequestSubscriber implements EventSubscriberInterface {
+
+  /**
+   * The access manager.
+   *
+   * @var \Drupal\Core\Access\AccessManager
+   */
+  protected $accessManager;
+
+  /**
+   * The current user account.
+   *
+   * @var \Drupal\Core\Session\AccountInterface
+   */
+  protected $account;
+
+  /**
+   * The http methods that are available to check.
+   *
+   * @var string[]
+   */
+  protected $availableMethods = array(
+    'GET',
+    'POST',
+    'PUT',
+    'DELETE',
+    'HEAD',
+    'PATCH',
+  );
+
+  /**
+   * Constructs an options request subscriber.
+   *
+   * @param \Drupal\Core\Access\AccessManager $access_manager
+   *   The access manager.
+   * @param \Drupal\Core\Session\AccountInterface $account
+   *   The current user account.
+   */
+  public function __construct(AccessManager $access_manager, AccountInterface $account) {
+    $this->accessManager = $access_manager;
+    $this->account = $account;
+  }
+
+  /**
+   * Handles OPTIONS requests.
+   */
+  public function onKernelRequest(GetResponseEvent $event) {
+    $request = $event->getRequest();
+    if ($request->getMethod() == 'OPTIONS') {
+      $allowed_methods = implode(' ', $this->getAllowedMethods($request));
+      $response = new Response(NULL, 200, array('Allow' => $allowed_methods));
+      $event->setResponse($response);
+      $event->stopPropagation();
+    }
+  }
+
+  /**
+   * Check which methods are allowed for the current request.
+   */
+  protected function getAllowedMethods(Request $request) {
+    $allow = array();
+    $route = $request->attributes->get(RouteObjectInterface::ROUTE_OBJECT);
+    if (isset($route)) {
+      foreach ($this->availableMethods as $method) {
+        $request->setMethod($method);
+        if ($this->accessManager->check($route, $request, $this->account)) {
+          $allow[] = $method;
+        }
+      }
+    }
+    return $allow;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getSubscribedEvents() {
+    $events[KernelEvents::REQUEST][] = array('onKernelRequest', 1000);
+    return $events;
+  }
+
+}
