diff --git a/core/modules/rest/lib/Drupal/rest/Plugin/rest/resource/EntityResource.php b/core/modules/rest/lib/Drupal/rest/Plugin/rest/resource/EntityResource.php
index 2b246b7..42d0335 100644
--- a/core/modules/rest/lib/Drupal/rest/Plugin/rest/resource/EntityResource.php
+++ b/core/modules/rest/lib/Drupal/rest/Plugin/rest/resource/EntityResource.php
@@ -86,6 +86,36 @@ public function post($id, EntityInterface $entity) {
   }
 
   /**
+   * Responds to entity PUT requests.
+   *
+   * @param mixed $id
+   *   The entity ID.
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity.
+   *
+   * @return \Drupal\rest\ResourceResponse
+   *   The HTTP response object.
+   *
+   * @throws \Symfony\Component\HttpKernel\Exception\HttpException
+   */
+  public function put($id, EntityInterface $entity) {
+    if (empty($id)) {
+      throw new NotFoundHttpException();
+    }
+    $info = $entity->entityInfo();
+    // Make sure that the entity ID is the one provided in the URL.
+    $entity->{$info['entity_keys']['id']} = $id;
+    try {
+      $entity->save();
+      // Update responses have an empty body.
+      return new ResourceResponse(NULL, 200);
+    }
+    catch (EntityStorageException $e) {
+      throw new HttpException(500, 'Internal Server Error', $e);
+    }
+  }
+
+  /**
    * Responds to entity DELETE requests.
    *
    * @param mixed $id
diff --git a/core/modules/rest/lib/Drupal/rest/Tests/CreateTest.php b/core/modules/rest/lib/Drupal/rest/Tests/CreateTest.php
index f5ef159..82f9685 100644
--- a/core/modules/rest/lib/Drupal/rest/Tests/CreateTest.php
+++ b/core/modules/rest/lib/Drupal/rest/Tests/CreateTest.php
@@ -63,8 +63,9 @@ public function testCreate() {
     // entity references is implemented.
     unset($entity_values['user_id']);
     foreach ($entity_values as $property => $value) {
-      $actual_value = $loaded_entity->get($property);
-      $this->assertEqual($value, $actual_value->value, 'Created property ' . $property . ' expected: ' . $value . ', actual: ' . $actual_value->value);
+      $actual_value = $loaded_entity->{$property}->value;
+      $create_value = $entity->{$property}->value;
+      $this->assertEqual($create_value, $actual_value, 'Created property ' . $property . ' expected: ' . $create_value . ', actual: ' . $actual_value);
     }
 
     // Try to create an entity without proper permissions.
diff --git a/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php b/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php
index 3640e48..78803c8 100644
--- a/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php
+++ b/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php
@@ -126,7 +126,11 @@ protected function entityCreate($entity_type) {
   protected function entityValues($entity_type) {
     switch ($entity_type) {
       case 'entity_test':
-        return array('name' => $this->randomName(), 'user_id' => 1);
+        return array(
+          'name' => $this->randomName(),
+          'user_id' => 1,
+          'field_test_text' => array(0 => array('value' => $this->randomString())),
+        );
       case 'node':
         return array('title' => $this->randomString());
       case 'user':
diff --git a/core/modules/rest/lib/Drupal/rest/Tests/UpdateTest.php b/core/modules/rest/lib/Drupal/rest/Tests/UpdateTest.php
new file mode 100644
index 0000000..1340d79
--- /dev/null
+++ b/core/modules/rest/lib/Drupal/rest/Tests/UpdateTest.php
@@ -0,0 +1,98 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\rest\test\UpdateTest.
+ */
+
+namespace Drupal\rest\Tests;
+
+use Drupal\rest\Tests\RESTTestBase;
+
+/**
+ * Tests resource updates on test entities.
+ */
+class UpdateTest extends RESTTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('rest', 'entity_test');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Update resource',
+      'description' => 'Tests the update of resources.',
+      'group' => 'REST',
+    );
+  }
+
+  /**
+   * Tests several valid and invalid update requests on test entities.
+   */
+  public function testUpdate() {
+    $serializer = drupal_container()->get('serializer');
+    // @todo once EntityNG is implemented for other entity types test all other
+    // entity types here as well.
+    $entity_type = 'entity_test';
+
+    $this->enableService('entity:' . $entity_type);
+    // Create a user account that has the required permissions to create
+    // resources via the web API.
+    $account = $this->drupalCreateUser(array('restful put entity:' . $entity_type));
+    $this->drupalLogin($account);
+
+    // Create an entity and save it to the database.
+    $entity = $this->entityCreate($entity_type);
+    $entity->save();
+
+    // Create a second entity that will overwrite the original.
+    $update_values = $this->entityValues($entity_type);
+    $update_entity = entity_create($entity_type, $update_values);
+    // Copy the identifier properties over from the original.
+    $update_entity->uuid->value = $entity->uuid();
+    $update_entity->id->value = $entity->id();
+
+    $serialized = $serializer->serialize($update_entity, 'drupal_jsonld');
+    // Update the entity over the web API.
+    $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'PUT', $serialized, 'application/vnd.drupal.ld+json');
+    $this->assertResponse(200);
+
+    // Re-load the updated entity from the database.
+    $entity = entity_load($entity_type, $entity->id(), TRUE);
+    // @todo Don't check the user reference field for now until deserialization
+    // for entity references is implemented.
+    unset($update_values['user_id']);
+    foreach ($update_values as $property => $value) {
+      $update_value = $update_entity->{$property}->value;
+      $stored_value = $entity->{$property}->value;
+      $this->assertEqual($stored_value, $update_value, 'Updated property ' . $property . ' expected: ' . $update_value . ', actual: ' . $stored_value);
+    }
+
+    // Try to delete a property.
+    unset($update_entity->field_test_text);
+    $serialized = $serializer->serialize($update_entity, 'drupal_jsonld');
+    $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'PUT', $serialized, 'application/vnd.drupal.ld+json');
+    $this->assertResponse(200);
+
+    // Re-load the updated entity from the database.
+    $entity = entity_load($entity_type, $entity->id(), TRUE);
+    $this->assertTrue($entity->field_test_text->isEmpty(), 'Property has been deleted.');
+
+    // Try to update an entity without proper permissions.
+    $this->drupalLogout();
+    $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'PUT', $serialized, 'application/vnd.drupal.ld+json');
+    $this->assertResponse(403);
+
+    // Try to update a resource which is not web API enabled.
+    $this->enableService(FALSE);
+    // Reset cURL here because it is confused from our previously used cURL
+    // options.
+    unset($this->curlHandle);
+    $this->drupalLogin($account);
+    $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'PUT', $serialized, 'application/vnd.drupal.ld+json');
+    $this->assertResponse(404);
+  }
+}
