diff --git a/core/modules/rdf/rdf.module b/core/modules/rdf/rdf.module
index 4c5f98b..3108ee1 100644
--- a/core/modules/rdf/rdf.module
+++ b/core/modules/rdf/rdf.module
@@ -233,9 +233,12 @@ function rdf_comment_storage_load($comments) {
     // to optimize performance for websites that implement an entity cache.
     $created_mapping = rdf_get_mapping('comment', $comment->bundle())
       ->getPreparedFieldMapping('created');
+    /** @var \Drupal\comment\CommentInterface $comment*/
     $comment->rdf_data['date'] = rdf_rdfa_attributes($created_mapping, $comment->get('created')->first()->toArray());
     $entity = $comment->getCommentedEntity();
-    $comment->rdf_data['entity_uri'] = $entity->url();
+    // The current function is a storage level hook, so avoid to bubble
+    // bubbleable metadata, because it can be outside of a render context.
+    $comment->rdf_data['entity_uri'] = $entity->toUrl()->toString(TRUE)->getGeneratedUrl();
     if ($comment->hasParentComment()) {
       $comment->rdf_data['pid_uri'] = $comment->getParentComment()->url();
     }
diff --git a/core/modules/rest/src/Plugin/rest/resource/EntityResource.php b/core/modules/rest/src/Plugin/rest/resource/EntityResource.php
index b4e78a4..d6fdcd1 100644
--- a/core/modules/rest/src/Plugin/rest/resource/EntityResource.php
+++ b/core/modules/rest/src/Plugin/rest/resource/EntityResource.php
@@ -146,13 +146,24 @@ public function patch(EntityInterface $original_entity, EntityInterface $entity
     }
 
     // Overwrite the received properties.
-    $langcode_key = $entity->getEntityType()->getKey('langcode');
+    $entity_keys = $entity->getEntityType()->getKeys();
     foreach ($entity->_restSubmittedFields as $field_name) {
       $field = $entity->get($field_name);
-      // It is not possible to set the language to NULL as it is automatically
-      // re-initialized. As it must not be empty, skip it if it is.
-      if ($field_name == $langcode_key && $field->isEmpty()) {
-        continue;
+
+      // Entity key fields need special treatment: together they uniquely
+      // identify the entity. Therefore it does not make sense to modify any of
+      // them. However, rather than throwing an error, we just ignore them as
+      // long as their specified values match their current values.
+      if (in_array($field_name, $entity_keys, TRUE)) {
+        // Unchanged values for entity keys don't need access checking.
+        if ($original_entity->get($field_name)->getValue() === $entity->get($field_name)->getValue()) {
+          continue;
+        }
+        // It is not possible to set the language to NULL as it is automatically
+        // re-initialized. As it must not be empty, skip it if it is.
+        else if (isset($entity_keys['langcode']) && $field_name === $entity_keys['langcode'] && $field->isEmpty()) {
+          continue;
+        }
       }
 
       if (!$original_entity->get($field_name)->access('edit')) {
diff --git a/core/modules/rest/src/Tests/RESTTestBase.php b/core/modules/rest/src/Tests/RESTTestBase.php
index 71b1a08..092af7c 100644
--- a/core/modules/rest/src/Tests/RESTTestBase.php
+++ b/core/modules/rest/src/Tests/RESTTestBase.php
@@ -250,8 +250,8 @@ protected function entityValues($entity_type) {
    *   resource types.
    * @param string $method
    *   The HTTP method to enable, e.g. GET, POST etc.
-   * @param string $format
-   *   (Optional) The serialization format, e.g. hal_json.
+   * @param string|array $format
+   *   (Optional) The serialization format, e.g. hal_json, or a list of formats.
    * @param array $auth
    *   (Optional) The list of valid authentication methods.
    */
@@ -261,10 +261,15 @@ protected function enableService($resource_type, $method = 'GET', $format = NULL
     $settings = array();
 
     if ($resource_type) {
-      if ($format == NULL) {
-        $format = $this->defaultFormat;
+      if (is_array($format)) {
+        $settings[$resource_type][$method]['supported_formats'] = $format;
+      }
+      else {
+        if ($format == NULL) {
+          $format = $this->defaultFormat;
+        }
+        $settings[$resource_type][$method]['supported_formats'][] = $format;
       }
-      $settings[$resource_type][$method]['supported_formats'][] = $format;
 
       if ($auth == NULL) {
         $auth = $this->defaultAuth;
diff --git a/core/modules/rest/src/Tests/UpdateTest.php b/core/modules/rest/src/Tests/UpdateTest.php
index e90da82..98df739 100644
--- a/core/modules/rest/src/Tests/UpdateTest.php
+++ b/core/modules/rest/src/Tests/UpdateTest.php
@@ -2,7 +2,12 @@
 
 namespace Drupal\rest\Tests;
 
+use Drupal\comment\Entity\Comment;
+use Drupal\comment\Tests\CommentTestTrait;
 use Drupal\Component\Serialization\Json;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\entity_test\Entity\EntityTest;
 
 /**
  * Tests the update of resources.
@@ -11,12 +16,22 @@
  */
 class UpdateTest extends RESTTestBase {
 
+  use CommentTestTrait;
+
   /**
    * Modules to install.
    *
    * @var array
    */
-  public static $modules = array('hal', 'rest', 'entity_test');
+  public static $modules = ['hal', 'rest', 'entity_test', 'comment'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->addDefaultCommentField('entity_test', 'entity_test');
+  }
 
   /**
    * Tests several valid and invalid partial update requests on test entities.
@@ -220,7 +235,129 @@ public function testUpdateUser() {
     // Verify that we can log in with the new password.
     $account->pass_raw = $new_password;
     $this->drupalLogin($account);
+  }
 
+  /**
+   * Test patching a comment using both HAL+JSON and JSON.
+   */
+  public function testUpdateComment() {
+    $entity_type = 'comment';
+    // Enables the REST service for 'comment' entity type.
+    $this->enableService('entity:' . $entity_type, 'PATCH', ['hal_json', 'json']);
+    $permissions = $this->entityPermissions($entity_type, 'update');
+    $permissions[] = 'restful patch entity:' . $entity_type;
+    $account = $this->drupalCreateUser($permissions);
+    $account->set('mail', 'old-email@example.com');
+    $this->drupalLogin($account);
+
+    // Create & save an entity to comment on, plus a comment.
+    $entity_test = EntityTest::create();
+    $entity_test->save();
+    $entity_values = $this->entityValues($entity_type);
+    $entity_values['entity_id'] = $entity_test->id();
+    $entity_values['uid'] = $account->id();
+    $comment = Comment::create($entity_values);
+    $comment->save();
+
+    $this->pass('Test case 1: PATCH comment using HAL+JSON.');
+    $comment->setSubject('Initial subject')->save();
+    $read_only_fields = [
+      'name',
+      'created',
+      'changed',
+      'status',
+      'thread',
+      'entity_type',
+      'field_name',
+      'entity_id',
+      'uid',
+    ];
+    $this->assertNotEqual('Updated subject', $comment->getSubject());
+    $comment->setSubject('Updated subject');
+    $this->patchEntity($comment, $read_only_fields, $account, 'hal_json', 'application/hal+json');
+    $comment = Comment::load($comment->id());
+    $this->assertEqual('Updated subject', $comment->getSubject());
+
+    $this->pass('Test case 1: PATCH comment using JSON.');
+    $comment->setSubject('Initial subject')->save();
+    $read_only_fields = [
+      'pid', // Extra compared to HAL+JSON.
+      'entity_id',
+      'uid',
+      'name',
+      'homepage', // Extra compared to HAL+JSON.
+      'created',
+      'changed',
+      'status',
+      'thread',
+      'entity_type',
+      'field_name',
+    ];
+    $this->assertNotEqual('Updated subject', $comment->getSubject());
+    $comment->setSubject('Updated subject');
+    $this->patchEntity($comment, $read_only_fields, $account, 'json', 'application/json');
+    $comment = Comment::load($comment->id());
+    $this->assertEqual('Updated subject', $comment->getSubject());
+  }
+
+  /**
+   * Patches an existing entity using the passed in (modified) entity.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The updated entity to send.
+   * @param string[] $read_only_fields
+   *   Names of the fields that are read-only, in validation order.
+   * @param \Drupal\Core\Session\AccountInterface $account
+   *   The account to use for serialization.
+   * @param string $format
+   *   A serialization format.
+   * @param string $mime_type
+   *   The MIME type corresponding to the specified serialization format.
+   */
+  protected function patchEntity(EntityInterface $entity, array $read_only_fields, AccountInterface $account, $format, $mime_type) {
+    $serializer = $this->container->get('serializer');
+
+    $url = $entity->toUrl();
+    $context = ['account' => $account];
+    // Certain fields are always read-only, others this user simply is not
+    // allowed to modify. For all of them, ensure they are not serialized, else
+    // we'll get a 403 plus an error message.
+    for ($i = 0; $i < count($read_only_fields); $i++) {
+      $field = $read_only_fields[$i];
+
+      $normalized = $serializer->normalize($entity, $format, $context);
+      if ($format !== 'hal_json') {
+        // The default normalizer always keeps fields, even if they are unset
+        // here because they should be omitted during a PATCH request. Therefore
+        // manually strip them
+        // @see \Drupal\Core\Entity\ContentEntityBase::__unset()
+        // @see \Drupal\serialization\Normalizer\EntityNormalizer::normalize()
+        // @see \Drupal\hal\Normalizer\ContentEntityNormalizer::normalize()
+        $read_only_fields_so_far = array_slice($read_only_fields, 0, $i);
+        $normalized = array_diff_key($normalized, array_flip($read_only_fields_so_far));
+      }
+      $serialized = $serializer->serialize($normalized, $format, $context);
+
+      $this->httpRequest($url, 'PATCH', $serialized, $mime_type);
+      $this->assertResponse(403);
+      $this->assertResponseBody('{"error":"Access denied on updating field \'' . $field . '\'."}');
+
+      if ($format === 'hal_json') {
+        // We've just tried with this read-only field, now unset it.
+        $entity->set($field, NULL);
+      }
+    }
+
+    // Finally, with all read-only fields unset, the request should succeed.
+    $normalized = $serializer->normalize($entity, $format, $context);
+    if ($format !== 'hal_json') {
+      $normalized = array_diff_key($normalized, array_combine($read_only_fields, $read_only_fields));
+    }
+    $serialized = $serializer->serialize($normalized, $format, $context);
+
+    $this->httpRequest($url, 'PATCH', $serialized, $mime_type);
+    $this->assertResponse(204);
+    $this->assertResponseBody('');
   }
 
 }
