diff --git a/core/lib/Drupal/Core/Entity/EntityNG.php b/core/lib/Drupal/Core/Entity/EntityNG.php
index 35ef89d20e1e33b05b63731bf6290eada3a24c15..c486aa8ddcf25f6f0024531f3c8e9cbd7706acc2 100644
--- a/core/lib/Drupal/Core/Entity/EntityNG.php
+++ b/core/lib/Drupal/Core/Entity/EntityNG.php
@@ -368,7 +368,7 @@ public function __isset($name) {
       return isset($this->values[$name]);
     }
     elseif ($this->getPropertyDefinition($name)) {
-      return (bool) count($this->get($name));
+      return $this->get($name)->valueIsSet();
     }
   }
 
@@ -380,7 +380,7 @@ public function __unset($name) {
       unset($this->values[$name]);
     }
     elseif ($this->getPropertyDefinition($name)) {
-      $this->get($name)->setValue(array());
+      $this->get($name)->unsetValue();
     }
   }
 
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/Field.php b/core/lib/Drupal/Core/Entity/Field/Type/Field.php
index cc5951c878c77ca3bb9f9cadc07bbd79114b6c1b..0e7a982e64f4d107265f9081dbcdd009784ada61 100644
--- a/core/lib/Drupal/Core/Entity/Field/Type/Field.php
+++ b/core/lib/Drupal/Core/Entity/Field/Type/Field.php
@@ -50,6 +50,13 @@ class Field extends TypedData implements IteratorAggregate, FieldInterface {
    */
   protected $list = array();
 
+  /**
+   * Flag to indicate if this field has been set.
+   *
+   * @var bool
+   */
+  protected $isset = FALSE;
+
   /**
    * Implements TypedDataInterface::getValue().
    */
@@ -68,6 +75,7 @@ public function getValue() {
    *   An array of values of the field items.
    */
   public function setValue($values) {
+    $this->isset = TRUE;
     if (isset($values) && $values !== array()) {
       // Support passing in only the value of the first item.
       if (!is_array($values) || !is_numeric(current(array_keys($values)))) {
@@ -100,6 +108,14 @@ public function setValue($values) {
     }
   }
 
+  /**
+   * Mark this field as not set.
+   */
+  public function unsetValue() {
+    $this->list = array();
+    $this->isset = FALSE;
+  }
+
   /**
    * Returns a string representation of the field.
    *
@@ -256,13 +272,14 @@ public function get($property_name) {
    */
   public function __set($property_name, $value) {
     $this->offsetGet(0)->__set($property_name, $value);
+    $this->isset = TRUE;
   }
 
   /**
    * Delegate.
    */
   public function __isset($property_name) {
-    return $this->offsetGet(0)->__isset($property_name);
+    return $this->isset && $this->offsetGet(0)->__isset($property_name);
   }
 
   /**
@@ -284,6 +301,15 @@ public function isEmpty() {
     return TRUE;
   }
 
+  /**
+   * Determines if this field has been set.
+   *
+   * @return bool
+   */
+  public function valueIsSet() {
+    return $this->isset;
+  }
+
   /**
    * Implements a deep clone.
    */
diff --git a/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityNormalizer.php b/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityNormalizer.php
index 2ab909e7ec5c674cdd630eedcfdd1dea9d78e792..d2fee3ad6c89e9bd905dfec0ac829d6aaa3ef895 100644
--- a/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityNormalizer.php
+++ b/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityNormalizer.php
@@ -79,11 +79,17 @@ public function denormalize($data, $class, $format = null) {
       if ($fieldName[0] === '@') {
         continue;
       }
+      // If the incoming value is an empty array we set the property to mark it
+      // for deletion.
+      if (empty($incomingFieldValues) && is_array($incomingFieldValues)) {
+        $entity->{$fieldName} = array();
+      }
 
       // Figure out the designated class for this field type, which is used by
       // the Serializer to determine which Denormalizer to use.
       // @todo Is there a better way to get the field type's associated class?
       $fieldItemClass = get_class($entity->get($fieldName)->offsetGet(0));
+
       // Iterate through the language keyed values and add them to the entity.
       // The vnd.drupal.ld+json mime type will always use language keys, per
       // http://drupal.org/node/1838700.
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 2b246b75d9610e9bddfe8fc97da909f40f932aec..bf8c7c1c02017181a81e8792b4bd8c6b220f2391 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
@@ -85,6 +85,49 @@ public function post($id, EntityInterface $entity) {
     }
   }
 
+  /**
+   * Responds to entity PATCH 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 patch($id, EntityInterface $entity) {
+    if (empty($id)) {
+      throw new NotFoundHttpException();
+    }
+    $definition = $this->getDefinition();
+    if ($entity->entityType() != $definition['entity_type']) {
+      throw new BadRequestHttpException('Invalid entity type');
+    }
+    $original_entity = entity_load($definition['entity_type'], $id);
+    // We don't support creating entities with PATCH, so we throw an error if
+    // there is no existing entity.
+    if ($original_entity == FALSE) {
+      throw new NotFoundHttpException();
+    }
+    // Overwrite the received properties.
+    foreach ($entity->getProperties() as $name => $property) {
+      if (isset($entity->{$name})) {
+        $original_entity->{$name} = $property;
+      }
+    }
+    try {
+      $original_entity->save();
+      // Update responses have an empty body.
+      return new ResourceResponse(NULL, 204);
+    }
+    catch (EntityStorageException $e) {
+      throw new HttpException(500, 'Internal Server Error', $e);
+    }
+  }
+
   /**
    * Responds to entity DELETE requests.
    *
diff --git a/core/modules/rest/lib/Drupal/rest/Tests/CreateTest.php b/core/modules/rest/lib/Drupal/rest/Tests/CreateTest.php
index f5ef15908ce9068612c904ca7b1f2e26dcc20135..b47f296edf246baa2513e9dbb5be7eae7cd7da91 100644
--- a/core/modules/rest/lib/Drupal/rest/Tests/CreateTest.php
+++ b/core/modules/rest/lib/Drupal/rest/Tests/CreateTest.php
@@ -48,7 +48,7 @@ public function testCreate() {
     $entity = entity_create($entity_type, $entity_values);
     $serialized = $serializer->serialize($entity, 'drupal_jsonld');
     // Create the entity over the web API.
-    $response = $this->httpRequest('entity/' . $entity_type, 'POST', $serialized, 'application/vnd.drupal.ld+json');
+    $this->httpRequest('entity/' . $entity_type, 'POST', $serialized, 'application/vnd.drupal.ld+json');
     $this->assertResponse('201', 'HTTP response code is correct.');
 
     // Get the new entity ID from the location header and try to read it from
@@ -63,13 +63,14 @@ 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->get($property)->value;
+      $send_value = $entity->get($property)->value;
+      $this->assertEqual($send_value, $actual_value, 'Created property ' . $property . ' expected: ' . $send_value . ', actual: ' . $actual_value);
     }
 
     // Try to create an entity without proper permissions.
     $this->drupalLogout();
-    $response = $this->httpRequest('entity/' . $entity_type, 'POST', $serialized, 'application/vnd.drupal.ld+json');
+    $this->httpRequest('entity/' . $entity_type, 'POST', $serialized, 'application/vnd.drupal.ld+json');
     $this->assertResponse(403);
 
     // Try to create a resource which is not web API enabled.
diff --git a/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php b/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php
index 0f8e7c68c9360790c2773f6ac780b97fb5ae7a74..c1a4d24098654cc1b7347572450f797efbc60f14 100644
--- a/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php
+++ b/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php
@@ -68,6 +68,17 @@ protected function httpRequest($url, $method, $body = NULL, $format = 'applicati
         );
         break;
 
+      case 'PATCH':
+        $curl_options = array(
+          CURLOPT_HTTPGET => FALSE,
+          CURLOPT_CUSTOMREQUEST => 'PATCH',
+          CURLOPT_POSTFIELDS => $body,
+          CURLOPT_URL => url($url, array('absolute' => TRUE)),
+          CURLOPT_NOBODY => FALSE,
+          CURLOPT_HTTPHEADER => array('Content-Type: ' . $format),
+        );
+        break;
+
       case 'DELETE':
         $curl_options = array(
           CURLOPT_HTTPGET => FALSE,
@@ -127,7 +138,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 0000000000000000000000000000000000000000..eed2b2ff744270dcd8f1c58160e3282595319d46
--- /dev/null
+++ b/core/modules/rest/lib/Drupal/rest/Tests/UpdateTest.php
@@ -0,0 +1,99 @@
+<?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 partial update requests on test entities.
+   */
+  public function testPatchUpdate() {
+    $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 patch 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 stub entity for overwriting a field.
+    $patch_values['field_test_text'] = array(0 => array('value' => $this->randomString()));
+    $patch_entity = entity_create($entity_type, $patch_values);
+    // We don't want to overwrite the UUID.
+    unset($patch_entity->uuid);
+    $serialized = $serializer->serialize($patch_entity, 'drupal_jsonld');
+
+    // Update the entity over the web API.
+    $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'PATCH', $serialized, 'application/vnd.drupal.ld+json');
+    $this->assertResponse(204);
+
+    // Re-load updated entity from the database.
+    $entity = entity_load($entity_type, $entity->id(), TRUE);
+    $this->assertEqual($entity->field_test_text->value, $patch_entity->field_test_text->value, 'Field was successfully updated.');
+
+    // Try to empty a field.
+    $normalized = $serializer->normalize($patch_entity, 'drupal_jsonld');
+    $normalized['field_test_text'] = array();
+    $serialized = $serializer->encode($normalized, 'jsonld');
+
+    // Update the entity over the web API.
+    $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'PATCH', $serialized, 'application/vnd.drupal.ld+json');
+    $this->assertResponse(204);
+
+    // Re-load updated entity from the database.
+    $entity = entity_load($entity_type, $entity->id(), TRUE);
+    $this->assertNull($entity->field_test_text->value, 'Test field has been cleared.');
+
+    // Try to update a non-existing entity with ID 9999.
+    $this->httpRequest('entity/' . $entity_type . '/9999', 'PATCH', $serialized, 'application/vnd.drupal.ld+json');
+    $this->assertResponse(404);
+    $loaded_entity = entity_load($entity_type, 9999, TRUE);
+    $this->assertFalse($loaded_entity, 'Entity 9999 was not created.');
+
+    // Try to update an entity without proper permissions.
+    $this->drupalLogout();
+    $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'PATCH', $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(), 'PATCH', $serialized, 'application/vnd.drupal.ld+json');
+    $this->assertResponse(404);
+  }
+}
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php
index a152bfa43e9cf124dc6ee23e11ea7b36792b3b6e..3dd810c7df3476f6ea2ec8731a117818106f4173 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php
@@ -128,6 +128,12 @@ public function testReadWrite() {
     $this->assertFalse(isset($entity->name[0]->value), 'Name is not set.');
     $this->assertFalse(isset($entity->name->value), 'Name is not set.');
 
+    $entity->name = array();
+    $this->assertTrue(isset($entity->name), 'Name field is set.');
+    $this->assertFalse(isset($entity->name[0]), 'Name field item is not set.');
+    $this->assertFalse(isset($entity->name[0]->value), 'First name item value is not set.');
+    $this->assertFalse(isset($entity->name->value), 'Name value is not set.');
+
     $entity->name->value = 'a value';
     $this->assertTrue(isset($entity->name->value), 'Name is set.');
     unset($entity->name);