diff --git a/core/modules/field/field.module b/core/modules/field/field.module
index 84fd041..05e11da 100644
--- a/core/modules/field/field.module
+++ b/core/modules/field/field.module
@@ -696,7 +696,7 @@ function template_preprocess_field(&$variables, $hook) {
   // formatters leave them within $element['#items'][$delta]['_attributes'] to
   // be rendered on the item wrappers provided by theme_field().
   foreach ($variables['items'] as $delta => $item) {
-    $variables['item_attributes'][$delta] = !empty($element['#items'][$delta]['_attributes']) ? new Attribute($element['#items'][$delta]['_attributes']) : clone($default_attributes);
+    $variables['item_attributes'][$delta] = !empty($element['#items'][$delta]['_attributes']['value']) ? new Attribute($element['#items'][$delta]['_attributes']['value']) : clone($default_attributes);
   }
 }
 
diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigEntityReferenceItemBase.php b/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigEntityReferenceItemBase.php
index 6b3c137..b4273c0 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigEntityReferenceItemBase.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigEntityReferenceItemBase.php
@@ -172,4 +172,15 @@ protected function getLegacyCallback($hook) {
     }
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function outputProperties() {
+    return array(
+      'value',
+      'type',
+      'label',
+    );
+  }
+
 }
diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigFieldItemBase.php b/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigFieldItemBase.php
index eb16d87..eaf6053 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigFieldItemBase.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigFieldItemBase.php
@@ -17,6 +17,13 @@
   /**
    * {@inheritdoc}
    */
+  public function outputProperties() {
+    return array('value');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function settingsForm(array $form, array &$form_state, $has_data) {
     return array();
   }
diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigFieldItemInterface.php b/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigFieldItemInterface.php
index 88de2ac..d77cc4b 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigFieldItemInterface.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigFieldItemInterface.php
@@ -50,6 +50,32 @@
   public static function schema(FieldInterface $field);
 
   /**
+   * Returns the output properties for the field.
+   *
+   * Field formatters typically process field data to generate an HTML output.
+   * The output of compound fields in particular is expected to be composed of
+   * several elements of information which are useful to be known in advance in
+   * case modules want to prepare attributes to wrap each individual elements of
+   * the output. An address field is composed of street, city and zip elements.
+   * An entity reference formatter will output a link with the referenced entity
+   * label. A text field can have multiple kinds of outputs: summary, trimmer or
+   * full text. Note that these output properties don't always match exactly the
+   * field schema: for example the text_format of a text field isn't part of the
+   * output as is, but is used to generate the content. Likewise, the label of a
+   * referenced entity isn't part of the entity reference field schema, but is
+   * relevant nonetheless to be acknowledged as an output property.
+   *
+   * @param \Drupal\field\FieldInterface $field
+   *   The field definition.
+   *
+   * @return array
+   *   A flat array of properties that field formatters may want to use when
+   *   generating their HTML output. Each field item passed to field formatters
+   *   will include these properties in $item->_attributes.
+   */
+  public function outputProperties();
+
+  /**
    * Returns a form for the field-level settings.
    *
    * Invoked from \Drupal\field_ui\Form\FieldEditForm to allow administrators to
diff --git a/core/modules/file/lib/Drupal/file/Plugin/field/field_type/FileItem.php b/core/modules/file/lib/Drupal/file/Plugin/field/field_type/FileItem.php
index eea8b44..d010530 100644
--- a/core/modules/file/lib/Drupal/file/Plugin/field/field_type/FileItem.php
+++ b/core/modules/file/lib/Drupal/file/Plugin/field/field_type/FileItem.php
@@ -324,4 +324,11 @@ public function isDisplayed() {
     return TRUE;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function outputProperties() {
+    return array('value');
+  }
+
 }
diff --git a/core/modules/file/lib/Drupal/file/Plugin/field/formatter/GenericFileFormatter.php b/core/modules/file/lib/Drupal/file/Plugin/field/formatter/GenericFileFormatter.php
index 3f61bc8..2386daa 100644
--- a/core/modules/file/lib/Drupal/file/Plugin/field/formatter/GenericFileFormatter.php
+++ b/core/modules/file/lib/Drupal/file/Plugin/field/formatter/GenericFileFormatter.php
@@ -38,9 +38,9 @@ public function viewElements(FieldItemListInterface $items) {
           '#description' => $item->description,
         );
         // Pass field item attributes to the theme function.
-        if (isset($item->_attributes)) {
+        if (isset($item->_attributes['value'])) {
           $elements[$delta] += array('#attributes' => array());
-          $elements[$delta]['#attributes'] += $item->_attributes;
+          $elements[$delta]['#attributes'] += $item->_attributes['value'];
           // Unset field item attributes since they have been included in the
           // formatter output and should not be rendered in the field template.
           unset($item->_attributes);
diff --git a/core/modules/forum/config/rdf.mapping.node.forum.yml b/core/modules/forum/config/rdf.mapping.node.forum.yml
index fc47f15..6f7c32e 100644
--- a/core/modules/forum/config/rdf.mapping.node.forum.yml
+++ b/core/modules/forum/config/rdf.mapping.node.forum.yml
@@ -5,29 +5,35 @@ types:
   - 'schema:Discussion'
 fieldMappings:
   title:
-    properties:
-      - 'schema:name'
+    value:
+      properties:
+        - 'schema:name'
   created:
-    properties:
-      - 'schema:dateCreated'
-    datatype_callback:
-      callable: 'date_iso8601'
+    value:
+      properties:
+        - 'schema:dateCreated'
+      datatype_callback:
+        callable: 'date_iso8601'
   changed:
-    properties:
-      - 'schema:dateModified'
-    datatype_callback:
-      callable: 'date_iso8601'
+    value:
+      properties:
+        - 'schema:dateModified'
+      datatype_callback:
+        callable: 'date_iso8601'
   body:
-    properties:
-      - 'schema:text'
+    value:
+      properties:
+        - 'schema:text'
   uid:
-    properties:
-      - 'schema:author'
-    mapping_type: 'rel'
+    value:
+      properties:
+        - 'schema:author'
+      mapping_type: 'rel'
   comment_count:
-    properties:
-      - 'schema:interactionCount'
-    datatype_callback:
-      callable: 'Drupal\rdf\SchemaOrgDataConverter::interactionCount'
-      arguments:
-        interaction_type: 'UserComments'
+    value:
+      properties:
+        - 'schema:interactionCount'
+      datatype_callback:
+        callable: 'Drupal\rdf\SchemaOrgDataConverter::interactionCount'
+        arguments:
+          interaction_type: 'UserComments'
diff --git a/core/modules/forum/config/rdf.mapping.taxonomy_term.forums.yml b/core/modules/forum/config/rdf.mapping.taxonomy_term.forums.yml
index aaaf536..b8cbf54 100644
--- a/core/modules/forum/config/rdf.mapping.taxonomy_term.forums.yml
+++ b/core/modules/forum/config/rdf.mapping.taxonomy_term.forums.yml
@@ -6,8 +6,10 @@ types:
   - 'sioc:Forum'
 fieldMappings:
   name:
-    properties:
-      - 'schema:name'
+    value:
+      properties:
+        - 'schema:name'
   description:
-    properties:
-      - 'schema:description'
+    value:
+      properties:
+        - 'schema:description'
diff --git a/core/modules/image/lib/Drupal/image/Plugin/field/formatter/ImageFormatter.php b/core/modules/image/lib/Drupal/image/Plugin/field/formatter/ImageFormatter.php
index 8659511..f5cea8a 100644
--- a/core/modules/image/lib/Drupal/image/Plugin/field/formatter/ImageFormatter.php
+++ b/core/modules/image/lib/Drupal/image/Plugin/field/formatter/ImageFormatter.php
@@ -120,9 +120,9 @@ public function viewElements(FieldItemListInterface $items) {
           '#path' => isset($uri) ? $uri : '',
         );
         // Pass field item attributes to the theme function.
-        if (isset($item->_attributes)) {
+        if (isset($item->_attributes['value'])) {
           $elements[$delta]['#item'] += array('attributes' => array());
-          $elements[$delta]['#item']['attributes'] += $item->_attributes;
+          $elements[$delta]['#item']['attributes'] += $item->_attributes['value'];
           // Unset field item attributes since they have been included in the
           // formatter output and should not be rendered in the field template.
           unset($item->_attributes);
diff --git a/core/modules/rdf/lib/Drupal/rdf/Entity/RdfMapping.php b/core/modules/rdf/lib/Drupal/rdf/Entity/RdfMapping.php
index 9464a56..ee7cd67 100644
--- a/core/modules/rdf/lib/Drupal/rdf/Entity/RdfMapping.php
+++ b/core/modules/rdf/lib/Drupal/rdf/Entity/RdfMapping.php
@@ -111,10 +111,12 @@ public function setBundleMapping(array $mapping) {
    */
   public function getPreparedFieldMapping($field_name) {
     $field_mapping = array(
-      'properties' => NULL,
-      'datatype' => NULL,
-      'datatype_callback' => NULL,
-      'mapping_type' => NULL,
+      'value' => array(
+        'properties' => NULL,
+        'datatype' => NULL,
+        'datatype_callback' => NULL,
+        'mapping_type' => NULL,
+      ),
     );
     if (isset($this->fieldMappings[$field_name])) {
       $field_mapping = array_merge($field_mapping, $this->fieldMappings[$field_name]);
diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/CommentAttributesTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/CommentAttributesTest.php
index 8a6b8c7..1df2014 100644
--- a/core/modules/rdf/lib/Drupal/rdf/Tests/CommentAttributesTest.php
+++ b/core/modules/rdf/lib/Drupal/rdf/Tests/CommentAttributesTest.php
@@ -52,50 +52,68 @@ public function setUp() {
     // Set relation between node and comment.
     $article_mapping = rdf_get_mapping('node', 'article');
     $comment_count_mapping = array(
-      'properties' => array('sioc:num_replies'),
-      'datatype' => 'xsd:integer',
-      'datatype_callback' => array('callable' => 'Drupal\rdf\CommonDataConverter::rawValue'),
+      'value' => array(
+        'properties' => array('sioc:num_replies'),
+        'datatype' => 'xsd:integer',
+        'datatype_callback' => array('callable' => 'Drupal\rdf\CommonDataConverter::rawValue'),
+      ),
     );
     $article_mapping->setFieldMapping('comment_count', $comment_count_mapping)->save();
 
     // Save user mapping.
     $user_mapping = rdf_get_mapping('user', 'user');
     $username_mapping = array(
-      'properties' => array('foaf:name'),
+      'value' => array(
+        'properties' => array('foaf:name'),
+      ),
     );
     $user_mapping->setFieldMapping('name', $username_mapping)->save();
-    $user_mapping->setFieldMapping('homepage', array('properties' => array('foaf:page'), 'mapping_type' => 'rel'))->save();
+    $user_mapping->setFieldMapping('homepage', array('value' => array('properties' => array('foaf:page'), 'mapping_type' => 'rel')))->save();
 
     // Save comment mapping.
     $mapping = rdf_get_mapping('comment', 'node__comment');
     $mapping->setBundleMapping(array('types' => array('sioc:Post', 'sioct:Comment')))->save();
     $field_mappings = array(
       'subject' => array(
-        'properties' => array('dc:title'),
+        'value' => array(
+          'properties' => array('dc:title'),
+        ),
       ),
       'created' => array(
-        'properties' => array('dc:date', 'dc:created'),
-        'datatype' => 'xsd:dateTime',
-        'datatype_callback' => array('callable' => 'date_iso8601'),
+        'value' => array(
+          'properties' => array('dc:date', 'dc:created'),
+          'datatype' => 'xsd:dateTime',
+          'datatype_callback' => array('callable' => 'date_iso8601'),
+        ),
       ),
       'changed' => array(
-        'properties' => array('dc:modified'),
-        'datatype' => 'xsd:dateTime',
-        'datatype_callback' => array('callable' => 'date_iso8601'),
+        'value' => array(
+          'properties' => array('dc:modified'),
+          'datatype' => 'xsd:dateTime',
+          'datatype_callback' => array('callable' => 'date_iso8601'),
+        ),
       ),
       'comment_body' => array(
-        'properties' => array('content:encoded'),
+        'value' => array(
+          'properties' => array('content:encoded'),
+        ),
       ),
       'pid' => array(
-        'properties' => array('sioc:reply_of'),
-        'mapping_type' => 'rel',
+        'value' => array(
+          'properties' => array('sioc:reply_of'),
+          'mapping_type' => 'rel',
+        ),
       ),
       'uid' => array(
-        'properties' => array('sioc:has_creator'),
-        'mapping_type' => 'rel',
+        'value' => array(
+          'properties' => array('sioc:has_creator'),
+          'mapping_type' => 'rel',
+        ),
       ),
       'name' => array(
-        'properties' => array('foaf:name'),
+        'value' => array(
+          'properties' => array('foaf:name'),
+        ),
       ),
     );
     // Iterate over shared field mappings and save.
diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/Field/FieldRdfaDatatypeCallbackTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/Field/FieldRdfaDatatypeCallbackTest.php
index 91153df..ebfd4ec 100644
--- a/core/modules/rdf/lib/Drupal/rdf/Tests/Field/FieldRdfaDatatypeCallbackTest.php
+++ b/core/modules/rdf/lib/Drupal/rdf/Tests/Field/FieldRdfaDatatypeCallbackTest.php
@@ -37,9 +37,11 @@ public function setUp() {
     // Add the mapping.
     $mapping = rdf_get_mapping('entity_test_render', 'entity_test_render');
     $mapping->setFieldMapping($this->fieldName, array(
-      'properties' => array('schema:interactionCount'),
-      'datatype_callback' => array(
-        'callable' => 'Drupal\rdf\Tests\Field\TestDataConverter::convertFoo',
+      'value' => array(
+        'properties' => array('schema:interactionCount'),
+        'datatype_callback' => array(
+          'callable' => 'Drupal\rdf\Tests\Field\TestDataConverter::convertFoo',
+        ),
       ),
     ))->save();
 
diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/Field/TaxonomyTermReferenceRdfaTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/Field/TaxonomyTermReferenceRdfaTest.php
index 38ee919..0d1ef96 100644
--- a/core/modules/rdf/lib/Drupal/rdf/Tests/Field/TaxonomyTermReferenceRdfaTest.php
+++ b/core/modules/rdf/lib/Drupal/rdf/Tests/Field/TaxonomyTermReferenceRdfaTest.php
@@ -88,7 +88,9 @@ public function setUp() {
     // Add the mapping.
     $mapping = rdf_get_mapping('entity_test_render', 'entity_test_render');
     $mapping->setFieldMapping($this->fieldName, array(
-      'properties' => array('schema:about'),
+      'value' => array(
+        'properties' => array('schema:about'),
+      ),
     ))->save();
 
     // Set up test values.
diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/FileFieldAttributesTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/FileFieldAttributesTest.php
index cc738e4..4aac991 100644
--- a/core/modules/rdf/lib/Drupal/rdf/Tests/FileFieldAttributesTest.php
+++ b/core/modules/rdf/lib/Drupal/rdf/Tests/FileFieldAttributesTest.php
@@ -65,7 +65,7 @@ public function setUp() {
 
     // Set the RDF mapping for the new field.
     $mapping = rdf_get_mapping('node', 'article');
-    $mapping->setFieldMapping($this->fieldName, array('properties' => array('rdfs:seeAlso'), 'mapping_type' => 'rel'))->save();
+    $mapping->setFieldMapping($this->fieldName, array('value' => array('properties' => array('rdfs:seeAlso'), 'mapping_type' => 'rel')))->save();
 
     $test_file = $this->getTestFile('text');
 
diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/ImageFieldAttributesTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/ImageFieldAttributesTest.php
index 14af8f6..a935587 100644
--- a/core/modules/rdf/lib/Drupal/rdf/Tests/ImageFieldAttributesTest.php
+++ b/core/modules/rdf/lib/Drupal/rdf/Tests/ImageFieldAttributesTest.php
@@ -62,8 +62,10 @@ public function setUp() {
     // Set the RDF mapping for the new field.
     rdf_get_mapping('node', 'article')
       ->setFieldMapping($this->fieldName, array(
-        'properties' => array('og:image'),
-        'mapping_type' => 'rel',
+        'value' => array(
+          'properties' => array('og:image'),
+          'mapping_type' => 'rel',
+        ),
       ))
       ->save();
 
diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/NodeAttributesTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/NodeAttributesTest.php
index 76e1af6..4a49ee4 100644
--- a/core/modules/rdf/lib/Drupal/rdf/Tests/NodeAttributesTest.php
+++ b/core/modules/rdf/lib/Drupal/rdf/Tests/NodeAttributesTest.php
@@ -37,12 +37,16 @@ public function setUp() {
         'types' => array('sioc:Item', 'foaf:Document'),
       ))
       ->setFieldMapping('title', array(
-        'properties' => array('dc:title'),
+        'value' => array(
+          'properties' => array('dc:title'),
+        ),
       ))
       ->setFieldMapping('created', array(
-        'properties' => array('dc:date', 'dc:created'),
-        'datatype' => 'xsd:dateTime',
-        'datatype_callback' => array('callable' => 'date_iso8601'),
+        'value' => array(
+          'properties' => array('dc:date', 'dc:created'),
+          'datatype' => 'xsd:dateTime',
+          'datatype_callback' => array('callable' => 'date_iso8601'),
+        ),
       ))
       ->save();
   }
diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/TaxonomyAttributesTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/TaxonomyAttributesTest.php
index 268a247..cefe22f 100644
--- a/core/modules/rdf/lib/Drupal/rdf/Tests/TaxonomyAttributesTest.php
+++ b/core/modules/rdf/lib/Drupal/rdf/Tests/TaxonomyAttributesTest.php
@@ -38,7 +38,9 @@ function setUp() {
     rdf_get_mapping('taxonomy_term', $this->vocabulary->id())
       ->setBundleMapping(array('types' => array('skos:Concept')))
       ->setFieldMapping('name', array(
-        'properties' => array('rdfs:label', 'skos:prefLabel'),
+        'value' => array(
+          'properties' => array('rdfs:label', 'skos:prefLabel'),
+        ),
       ))
       ->save();
   }
diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/TaxonomyTermFieldAttributesTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/TaxonomyTermFieldAttributesTest.php
index 9d62168..8096e7f 100644
--- a/core/modules/rdf/lib/Drupal/rdf/Tests/TaxonomyTermFieldAttributesTest.php
+++ b/core/modules/rdf/lib/Drupal/rdf/Tests/TaxonomyTermFieldAttributesTest.php
@@ -59,14 +59,16 @@ public function setUp() {
     // Set the RDF mapping for the new field.
     rdf_get_mapping('node', 'article')
       ->setFieldMapping($this->fieldName, array(
-        'properties' => array('dc:subject'),
-        'mapping_type' => 'rel',
+        'value' => array(
+          'properties' => array('dc:subject'),
+          'mapping_type' => 'rel',
+        ),
       ))
       ->save();
 
     rdf_get_mapping('taxonomy_term', $this->vocabulary->id())
       ->setBundleMapping(array('types' => array('skos:Concept')))
-      ->setFieldMapping('name', array('properties' => array('rdfs:label')))
+      ->setFieldMapping('name', array('value' => array('properties' => array('rdfs:label'))))
       ->save();
   }
 
diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/TrackerAttributesTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/TrackerAttributesTest.php
index b4a4082..9276327 100644
--- a/core/modules/rdf/lib/Drupal/rdf/Tests/TrackerAttributesTest.php
+++ b/core/modules/rdf/lib/Drupal/rdf/Tests/TrackerAttributesTest.php
@@ -41,36 +41,52 @@ function setUp() {
     // Set fields RDF mapping config for article.
     $node_shared_field_mappings = array(
       'title' => array(
-        'properties' => array('dc:title'),
+        'value' => array(
+          'properties' => array('dc:title'),
+        ),
       ),
       'created' => array(
-        'properties' => array('dc:date', 'dc:created'),
-        'datatype' => 'xsd:dateTime',
-        'datatype_callback' => array('callable' => 'date_iso8601'),
+        'value' => array(
+          'properties' => array('dc:date', 'dc:created'),
+          'datatype' => 'xsd:dateTime',
+          'datatype_callback' => array('callable' => 'date_iso8601'),
+        ),
       ),
       'changed' => array(
-        'properties' => array('dc:modified'),
-        'datatype' => 'xsd:dateTime',
-        'datatype_callback' => array('callable' => 'date_iso8601'),
+        'value' => array(
+          'properties' => array('dc:modified'),
+          'datatype' => 'xsd:dateTime',
+          'datatype_callback' => array('callable' => 'date_iso8601'),
+        ),
       ),
       'body' => array(
-        'properties' => array('content:encoded'),
+        'value' => array(
+          'properties' => array('content:encoded'),
+        ),
       ),
       'uid' => array(
-        'properties' => array('sioc:has_creator'),
-        'mapping_type' => 'rel',
+        'value' => array(
+          'properties' => array('sioc:has_creator'),
+          'mapping_type' => 'rel',
+        ),
       ),
       'name' => array(
-        'properties' => array('foaf:name'),
+        'value' => array(
+          'properties' => array('foaf:name'),
+        ),
       ),
       'comment_count' => array(
-        'properties' => array('sioc:num_replies'),
-        'datatype' => 'xsd:integer',
+        'value' => array(
+          'properties' => array('sioc:num_replies'),
+          'datatype' => 'xsd:integer',
+        ),
       ),
       'last_activity' => array(
-        'properties' => array('sioc:last_activity_date'),
-        'datatype' => 'xsd:dateTime',
-        'datatype_callback' => array('callable' => 'date_iso8601'),
+        'value' => array(
+          'properties' => array('sioc:last_activity_date'),
+          'datatype' => 'xsd:dateTime',
+          'datatype_callback' => array('callable' => 'date_iso8601'),
+        ),
       ),
     );
     // Iterate over field mappings and save.
diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/UserAttributesTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/UserAttributesTest.php
index 073490d..6efc69a 100644
--- a/core/modules/rdf/lib/Drupal/rdf/Tests/UserAttributesTest.php
+++ b/core/modules/rdf/lib/Drupal/rdf/Tests/UserAttributesTest.php
@@ -36,7 +36,9 @@ public function setUp() {
         'types' => array('sioc:UserAccount'),
       ))
       ->setFieldMapping('name', array(
-        'properties' => array('foaf:name'),
+        'value' => array(
+          'properties' => array('foaf:name'),
+        ),
       ))
       ->save();
   }
diff --git a/core/modules/rdf/rdf.module b/core/modules/rdf/rdf.module
index 08cd24c..05c4c88 100644
--- a/core/modules/rdf/rdf.module
+++ b/core/modules/rdf/rdf.module
@@ -208,9 +208,11 @@ function rdf_entity_prepare_view($entity_type, array $entities, array $displays)
     // be displayed.
     foreach ($displays[$entity->bundle()]->getComponents() as $name => $options) {
       $field_mapping = $mapping->getPreparedFieldMapping($name);
-      if ($field_mapping['properties']) {
-        foreach ($entity->get($name) as $item) {
-          $item->_attributes += rdf_rdfa_attributes($field_mapping, $item->getValue());
+      foreach ($entity->get($name) as $item) {
+        foreach($item->outputProperties() as $output_property) {
+          if (!empty($field_mapping[$output_property]['properties'])) {
+            $item->_attributes = array_merge_recursive($item->_attributes, array($output_property => rdf_rdfa_attributes($field_mapping[$output_property], $item->getValue())));
+          }
         }
       }
     }
@@ -227,7 +229,9 @@ function rdf_comment_load($comments) {
     // to optimize performance for websites that implement an entity cache.
     $created_mapping = rdf_get_mapping('comment', $comment->bundle())
       ->getPreparedFieldMapping('created');
-    $comment->rdf_data['date'] = rdf_rdfa_attributes($created_mapping, $comment->created->value);
+    if (!empty($created_mapping['value'])) {
+      $comment->rdf_data['date'] = rdf_rdfa_attributes($created_mapping['value'], $comment->created->value);
+    }
     $entity = entity_load($comment->entity_type->value, $comment->entity_id->value);
     $uri = $entity->uri();
     $comment->rdf_data['entity_uri'] = url($uri['path']);
@@ -281,7 +285,7 @@ function rdf_preprocess_node(&$variables) {
   // the view mode (e.g. full vs. teaser).
   $title_mapping = $mapping->getPreparedFieldMapping('title');
   if ($title_mapping) {
-    $title_attributes['property'] = empty($title_mapping['properties']) ? NULL : $title_mapping['properties'];
+    $title_attributes['property'] = empty($title_mapping['value']['properties']) ? NULL : $title_mapping['value']['properties'];
     $title_attributes['content'] = $variables['node']->label();
     $variables['title_suffix']['rdf_meta_title'] = array(
       '#theme' => 'rdf_metadata',
@@ -291,15 +295,15 @@ function rdf_preprocess_node(&$variables) {
 
   // Adds RDFa markup for the relation between the node and its author.
   $author_mapping = $mapping->getPreparedFieldMapping('uid');
-  if (!empty($author_mapping['properties']) && $variables['submitted']) {
-    $author_attributes = array('rel' => $author_mapping['properties']);
+  if (!empty($author_mapping['value']['properties']) && $variables['submitted']) {
+    $author_attributes = array('rel' => $author_mapping['value']['properties']);
     $variables['submitted'] = '<span ' . new Attribute($author_attributes) . '>' . $variables['submitted'] . '</span>';
   }
 
   // Adds RDFa markup for the date.
   $created_mapping = $mapping->getPreparedFieldMapping('created');
-  if (!empty($created_mapping) && $variables['submitted']) {
-    $date_attributes = rdf_rdfa_attributes($created_mapping, $variables['node']->getCreatedTime());
+  if (!empty($created_mapping['value']) && $variables['submitted']) {
+    $date_attributes = rdf_rdfa_attributes($created_mapping['value'], $variables['node']->getCreatedTime());
     $rdf_metadata = array(
       '#theme' => 'rdf_metadata',
       '#metadata' => array($date_attributes),
@@ -310,7 +314,7 @@ function rdf_preprocess_node(&$variables) {
   // Adds RDFa markup annotating the number of comments a node has.
   $comment_count_mapping = $mapping->getPreparedFieldMapping('comment_count');
   if (\Drupal::moduleHandler()->moduleExists('comment')) {
-    if (!empty($comment_count_mapping['properties'])) {
+    if (!empty($comment_count_mapping['value']['properties'])) {
       $fields = array_keys(\Drupal::service('comment.manager')->getFields('node'));
       $definitions = array_keys($variables['node']->getPropertyDefinitions());
       $valid_fields = array_intersect($fields, $definitions);
@@ -319,7 +323,7 @@ function rdf_preprocess_node(&$variables) {
         $count += $variables['node']->get($field_name)->comment_count;
         // Annotates the 'x comments' link in teaser view.
         if (isset($variables['content']['links']['comment__' . $field_name]['#links']['comment-comments'])) {
-          $comment_count_attributes = rdf_rdfa_attributes($comment_count_mapping, $variables['node']->get($field_name)->comment_count);
+          $comment_count_attributes = rdf_rdfa_attributes($comment_count_mapping['value'], $variables['node']->get($field_name)->comment_count);
           // According to RDFa parsing rule number 4, a new subject URI is created
           // from the href attribute if no rel/rev attribute is present. To get
           // the original node URL from the about attribute of the parent
@@ -337,10 +341,7 @@ function rdf_preprocess_node(&$variables) {
           '#tag' => 'meta',
           '#attributes' => array(
             'about' => $variables['node_url'],
-            'property' => $comment_count_mapping['properties'],
-            'content' => $count,
-            'datatype' => $comment_count_mapping['datatype'],
-          ),
+          ) + rdf_rdfa_attributes($comment_count_mapping['value'], $count),
         );
         drupal_add_html_head($element, 'rdf_node_comment_count');
       }
@@ -369,12 +370,12 @@ function rdf_preprocess_user(&$variables) {
     // Adds the markup for username as language neutral literal, see
     // rdf_preprocess_username().
     $name_mapping = $mapping->getPreparedFieldMapping('name');
-    if (!empty($name_mapping['properties'])) {
+    if (!empty($name_mapping['value']['properties'])) {
       $username_meta = array(
         '#tag' => 'meta',
         '#attributes' => array(
           'about' => url($uri['path'], $uri['options']),
-          'property' => $name_mapping['properties'],
+          'property' => $name_mapping['value']['properties'],
           'content' => $account->getUsername(),
           'lang' => '',
         ),
@@ -419,14 +420,14 @@ function rdf_preprocess_username(&$variables) {
   // datatype attribute to ensure the username is parsed as a plain literal
   // in RDFa 1.0 and 1.1.
   $name_mapping = $mapping->getPreparedFieldMapping('name');
-  if (!empty($name_mapping)) {
-    $attributes['property'] = $name_mapping['properties'];
+  if (!empty($name_mapping['value']['properties'])) {
+    $attributes['property'] = $name_mapping['value']['properties'];
     $attributes['datatype'] = '';
   }
   // Add the homepage RDFa markup if present.
   $homepage_mapping = $mapping->getPreparedFieldMapping('homepage');
-  if (!empty($variables['homepage']) && !empty($homepage_mapping)) {
-    $attributes['rel'] = $homepage_mapping['properties'];
+  if (!empty($variables['homepage']) && !empty($homepage_mapping['value']['properties'])) {
+    $attributes['rel'] = $homepage_mapping['value']['properties'];
   }
   // The remaining attributes can have multiple values listed, with whitespace
   // separating the values in the RDFa attributes
@@ -462,8 +463,8 @@ function rdf_preprocess_comment(&$variables) {
 
   // Adds RDFa markup for the relation between the comment and its author.
   $author_mapping = $mapping->getPreparedFieldMapping('uid');
-  if (!empty($author_mapping)) {
-    $author_attributes = array('rel' => $author_mapping['properties']);
+  if (!empty($author_mapping['value'])) {
+    $author_attributes = array('rel' => $author_mapping['value']['properties']);
     // Wraps the author variable and the submitted variable which are both
     // available in comment.html.twig.
     $variables['author'] = '<span ' . new Attribute($author_attributes) . '>' . $variables['author'] . '</span>';
@@ -471,7 +472,7 @@ function rdf_preprocess_comment(&$variables) {
   }
   // Adds RDFa markup for the date of the comment.
   $created_mapping = $mapping->getPreparedFieldMapping('created');
-  if (!empty($created_mapping)) {
+  if (!empty($created_mapping['value'])) {
     // The comment date is precomputed as part of the rdf_data so that it can be
     // cached as part of the entity.
     $date_attributes = $comment->rdf_data['date'];
@@ -487,12 +488,12 @@ function rdf_preprocess_comment(&$variables) {
     $variables['submitted'] .= $created_metadata_markup;
   }
   $title_mapping = $mapping->getPreparedFieldMapping('subject');
-  if (!empty($title_mapping)) {
+  if (!empty($title_mapping['value'])) {
     // Adds RDFa markup to the subject of the comment. Because the RDFa markup
     // is added to an <h3> tag which might contain HTML code, we specify an
     // empty datatype to ensure the value of the title read by the RDFa parsers
     // is a literal.
-    $variables['title_attributes']['property'] = $title_mapping['properties'];
+    $variables['title_attributes']['property'] = $title_mapping['value']['properties'];
     $variables['title_attributes']['datatype'] = '';
   }
 
@@ -501,9 +502,9 @@ function rdf_preprocess_comment(&$variables) {
   // @todo When comments are turned into fields, this should be changed.
   // Currently there is no mapping relating a comment to its node.
   $pid_mapping = $mapping->getPreparedFieldMapping('pid');
-  if (!empty($pid_mapping)) {
+  if (!empty($pid_mapping['value']['properties'])) {
     // Adds the relation to the parent entity.
-    $parent_entity_attributes['rel'] = $pid_mapping['properties'];
+    $parent_entity_attributes['rel'] = $pid_mapping['value']['properties'];
     // The parent entity URI is precomputed as part of the rdf_data so that it
     // can be cached as part of the entity.
     $parent_entity_attributes['resource'] = $comment->rdf_data['entity_uri'];
@@ -511,7 +512,7 @@ function rdf_preprocess_comment(&$variables) {
 
     // Adds the relation to parent comment, if it exists.
     if ($comment->pid->target_id != 0) {
-      $parent_comment_attributes['rel'] = $pid_mapping['properties'];
+      $parent_comment_attributes['rel'] = $pid_mapping['value']['properties'];
       // The parent comment URI is precomputed as part of the rdf_data so that
       // it can be cached as part of the entity.
       $parent_comment_attributes['resource'] = $comment->rdf_data['pid_uri'];
@@ -545,7 +546,7 @@ function rdf_preprocess_taxonomy_term(&$variables) {
     '#attributes' => array(
       'about' => url('taxonomy/term/' . $term->id()),
       'typeof' => $bundle_mapping['types'],
-      'property' => $name_field_mapping['properties'],
+      'property' => $name_field_mapping['value']['properties'],
       'content' => $term->label(),
     ),
   );
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityViewControllerTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityViewControllerTest.php
index ca3ac07..73661fc 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityViewControllerTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityViewControllerTest.php
@@ -107,7 +107,9 @@ public function testFieldItemAttributes() {
     // be turned into RDFa attributes in the field item output.
     $mapping = rdf_get_mapping('entity_test_render', 'entity_test_render');
     $mapping->setFieldMapping('field_test_text', array(
-      'properties' => array('schema:text'),
+      'value' => array(
+        'properties' => array('schema:text'),
+      ),
     ))->save();
     // Browse to the entity and verify that the attributes from both modules
     // are rendered in the field item HTML markup.
diff --git a/core/modules/system/tests/modules/entity_test/entity_test.module b/core/modules/system/tests/modules/entity_test/entity_test.module
index cc8800e..1030cd9 100644
--- a/core/modules/system/tests/modules/entity_test/entity_test.module
+++ b/core/modules/system/tests/modules/entity_test/entity_test.module
@@ -545,7 +545,7 @@ function entity_test_entity_prepare_view($entity_type, array $entities, array $d
     foreach ($entities as $entity) {
       if ($entity->getPropertyDefinition('field_test_text')) {
         foreach ($entity->get('field_test_text') as $item) {
-          $item->_attributes += array('data-field-item-attr' => 'foobar');
+          $item->_attributes = array_merge_recursive($item->_attributes, array('value' => array('data-field-item-attr' => 'foobar')));
         }
       }
     }
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/field/formatter/LinkFormatter.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/field/formatter/LinkFormatter.php
index 60e79ef..0c94f64 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/field/formatter/LinkFormatter.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/field/formatter/LinkFormatter.php
@@ -49,9 +49,9 @@ public function viewElements(FieldItemListInterface $items) {
           '#options' => $uri['options'],
         );
 
-        if (!empty($item->_attributes)) {
+        if (!empty($item->_attributes['value'])) {
           $elements[$delta]['#options'] += array('attributes' => array());
-          $elements[$delta]['#options']['attributes'] += $item->_attributes;
+          $elements[$delta]['#options']['attributes'] += $item->_attributes['value'];
           // Unset field item attributes since they have been included in the
           // formatter output and should not be rendered in the field template.
           unset($item->_attributes);
diff --git a/core/modules/tracker/tracker.pages.inc b/core/modules/tracker/tracker.pages.inc
index 16b391e..160a6aa 100644
--- a/core/modules/tracker/tracker.pages.inc
+++ b/core/modules/tracker/tracker.pages.inc
@@ -108,27 +108,27 @@ function tracker_page($account = NULL, $set_title = FALSE) {
         // empty datatype to ensure the value of the title read by the RDFa
         // parsers is a plain literal.
         $title_mapping = $mapping->getPreparedFieldMapping('title');
-        $row['title'] += rdf_rdfa_attributes($title_mapping) + array('datatype' => '');
+        $row['title'] += rdf_rdfa_attributes($title_mapping['value']) + array('datatype' => '');
         // Annotates the td tag containing the author of the node.
         $uid_mapping = $mapping->getPreparedFieldMapping('uid');
-        $row['author'] += rdf_rdfa_attributes($uid_mapping);
+        $row['author'] += rdf_rdfa_attributes($uid_mapping['value']);
         // Annotates the td tag containing the number of replies. We add the
         // content attribute to ensure that only the comment count is used as
         // the value for 'num_replies'. Otherwise, other text such as a link
         // to the number of new comments could be included in the 'num_replies'
         // value.
         $comment_count_mapping = $mapping->getPreparedFieldMapping('comment_count');
-        $row['replies'] += rdf_rdfa_attributes($comment_count_mapping);
+        $row['replies'] += rdf_rdfa_attributes($comment_count_mapping['value']);
         $row['replies'] += array('content' => $node->comment_count);
         // If the node has no comments, we assume the node itself was modified
         // and apply 'changed' in addition to 'last_activity'.  If there are
         // comments present, we cannot infer whether the node itself was
         // modified or a comment was posted, so we use only 'last_activity'.
         $last_activity_mapping = $mapping->getPreparedFieldMapping('last_activity');
-        $last_activity_attributes = rdf_rdfa_attributes($last_activity_mapping, $node->last_activity);
+        $last_activity_attributes = rdf_rdfa_attributes($last_activity_mapping['value'], $node->last_activity);
         if ($node->comment_count == 0) {
           $changed_mapping = $mapping->getPreparedFieldMapping('changed');
-          $changed_attributes = rdf_rdfa_attributes($changed_mapping, $node->last_activity);
+          $changed_attributes = rdf_rdfa_attributes($changed_mapping['value'], $node->last_activity);
           $last_activity_attributes['property'] = array_merge($last_activity_attributes['property'], $changed_attributes['property']);
         }
         $row['last updated'] += $last_activity_attributes;
diff --git a/core/modules/user/config/rdf.mapping.user.user.yml b/core/modules/user/config/rdf.mapping.user.user.yml
index ad082a9..4869a82 100644
--- a/core/modules/user/config/rdf.mapping.user.user.yml
+++ b/core/modules/user/config/rdf.mapping.user.user.yml
@@ -5,5 +5,6 @@ types:
   - 'schema:Person'
 fieldMappings:
   name:
-    properties:
-      - 'schema:name'
+    value:
+      properties:
+        - 'schema:name'
diff --git a/core/profiles/standard/config/rdf.mapping.comment.node__comment.yml b/core/profiles/standard/config/rdf.mapping.comment.node__comment.yml
index 42d8f34..03ed6c6 100644
--- a/core/profiles/standard/config/rdf.mapping.comment.node__comment.yml
+++ b/core/profiles/standard/config/rdf.mapping.comment.node__comment.yml
@@ -5,22 +5,27 @@ types:
   - 'schema:Comment'
 fieldMappings:
   subject:
-    properties:
-      - 'schema:name'
+    value:
+      properties:
+        - 'schema:name'
   created:
-    properties:
-      - 'schema:dateCreated'
-    datatype_callback:
-      callable: 'date_iso8601'
+    value:
+      properties:
+        - 'schema:dateCreated'
+      datatype_callback:
+        callable: 'date_iso8601'
   changed:
-    properties:
-      - 'schema:dateModified'
-    datatype_callback:
-      callable: 'date_iso8601'
+    value:
+      properties:
+        - 'schema:dateModified'
+      datatype_callback:
+        callable: 'date_iso8601'
   comment_body:
-    properties:
-      - 'schema:text'
+    value:
+      properties:
+        - 'schema:text'
   uid:
-    properties:
-      - 'schema:author'
-    mapping_type: 'rel'
+    value:
+      properties:
+        - 'schema:author'
+      mapping_type: 'rel'
diff --git a/core/profiles/standard/config/rdf.mapping.node.article.yml b/core/profiles/standard/config/rdf.mapping.node.article.yml
index a87edaf..4ed3358 100644
--- a/core/profiles/standard/config/rdf.mapping.node.article.yml
+++ b/core/profiles/standard/config/rdf.mapping.node.article.yml
@@ -5,38 +5,47 @@ types:
   - 'schema:Article'
 fieldMappings:
   title:
-    properties:
-      - 'schema:name'
+    value:
+      properties:
+        - 'schema:name'
   created:
-    properties:
-      - 'schema:dateCreated'
-    datatype_callback:
-      callable: 'date_iso8601'
+    value:
+      properties:
+        - 'schema:dateCreated'
+      datatype_callback:
+        callable: date_iso8601
   changed:
-    properties:
-      - 'schema:dateModified'
-    datatype_callback:
-      callable: 'date_iso8601'
+    value:
+      properties:
+        - 'schema:dateModified'
+      datatype_callback:
+        callable: date_iso8601
   body:
-    properties:
-      - 'schema:text'
+    value:
+      properties:
+        - 'schema:text'
   uid:
-    properties:
-      - 'schema:author'
+    value:
+      properties:
+        - 'schema:author'
   comment:
-    properties:
-      - 'schema:comment'
-    mapping_type: 'rel'
+    value:
+      properties:
+        - 'schema:comment'
+      mapping_type: 'rel'
   comment_count:
-    properties:
-      - 'schema:interactionCount'
-    datatype_callback:
-      callable: 'Drupal\rdf\SchemaOrgDataConverter::interactionCount'
-      arguments:
-        interaction_type: 'UserComments'
+    value:
+      properties:
+        - 'schema:interactionCount'
+      datatype_callback:
+        callable: 'Drupal\rdf\SchemaOrgDataConverter::interactionCount'
+        arguments:
+          interaction_type: UserComments
   field_image:
-    properties:
-      - 'schema:image'
+    value:
+      properties:
+        - 'schema:image'
   field_tags:
-    properties:
-      - 'schema:about'
+    value:
+      properties:
+        - 'schema:about'
diff --git a/core/profiles/standard/config/rdf.mapping.node.page.yml b/core/profiles/standard/config/rdf.mapping.node.page.yml
index 967449c..7865017 100644
--- a/core/profiles/standard/config/rdf.mapping.node.page.yml
+++ b/core/profiles/standard/config/rdf.mapping.node.page.yml
@@ -5,29 +5,35 @@ types:
   - 'schema:WebPage'
 fieldMappings:
   title:
-    properties:
-      - 'schema:name'
+    value:
+      properties:
+        - 'schema:name'
   created:
-    properties:
-      - 'schema:dateCreated'
-    datatype_callback:
-      callable: 'date_iso8601'
+    value:
+      properties:
+        - 'schema:dateCreated'
+      datatype_callback:
+        callable: 'date_iso8601'
   changed:
-    properties:
-      - 'schema:dateModified'
-    datatype_callback:
-      callable: 'date_iso8601'
+    value:
+      properties:
+        - 'schema:dateModified'
+      datatype_callback:
+        callable: 'date_iso8601'
   body:
-    properties:
-      - 'schema:text'
+    value:
+      properties:
+        - 'schema:text'
   uid:
-    properties:
-      - 'schema:author'
-    mapping_type: 'rel'
+    value:
+      properties:
+        - 'schema:author'
+      mapping_type: 'rel'
   comment_count:
-    properties:
-      - 'schema:interactionCount'
-    datatype_callback:
-      callable: 'Drupal\rdf\SchemaOrgDataConverter::interactionCount'
-      arguments:
-        interaction_type: 'UserComments'
+    value:
+      properties:
+        - 'schema:interactionCount'
+      datatype_callback:
+        callable: 'Drupal\rdf\SchemaOrgDataConverter::interactionCount'
+        arguments:
+          interaction_type: 'UserComments'
diff --git a/core/profiles/standard/config/rdf.mapping.taxonomy_term.tags.yml b/core/profiles/standard/config/rdf.mapping.taxonomy_term.tags.yml
index 051795c..260dc93 100644
--- a/core/profiles/standard/config/rdf.mapping.taxonomy_term.tags.yml
+++ b/core/profiles/standard/config/rdf.mapping.taxonomy_term.tags.yml
@@ -5,8 +5,10 @@ types:
   - 'schema:Thing'
 fieldMappings:
   name:
-    properties:
-      - 'schema:name'
+    value:
+      properties:
+        - 'schema:name'
   description:
-    properties:
-      - 'schema:description'
+    value:
+      properties:
+        - 'schema:description'
