diff --git a/core/lib/Drupal/Core/Config/ConfigBase.php b/core/lib/Drupal/Core/Config/ConfigBase.php
index 3508611..b0db1b6 100644
--- a/core/lib/Drupal/Core/Config/ConfigBase.php
+++ b/core/lib/Drupal/Core/Config/ConfigBase.php
@@ -160,13 +160,39 @@ public function get($key = '') {
    *
    * @return $this
    *   The configuration object.
+   *
+   * @throws \Exception
+   *   If any key in $data in any depth contains a dot.
    */
   public function setData(array $data) {
+    $this->validateKeys($data);
     $this->data = $data;
     return $this;
   }
 
   /**
+   * Validate all keys in a passed in config array structure.
+   *
+   * @param array $data
+   *   Configuration array structure.
+   *
+   * @return null
+   *
+   * @throws \Exception
+   *   If any key in $data in any depth contains a dot.
+   */
+  protected function validateKeys(array $data) {
+    foreach ($data as $key => $value) {
+      if (strpos($key, '.') !== FALSE) {
+        throw new \Exception(String::format('@key key contains a dot which is not supported.', array('@key' => $key)));
+      }
+      if (is_array($value)) {
+        $this->validateKeys($value);
+      }
+    }
+  }
+
+  /**
    * Sets a value in this configuration object.
    *
    * @param string $key
@@ -176,10 +202,16 @@ public function setData(array $data) {
    *
    * @return $this
    *   The configuration object.
+   *
+   * @throws \Exception
+   *   If $value is an array and any of its keys in any depth contains a dot.
    */
   public function set($key, $value) {
     // The dot/period is a reserved character; it may appear between keys, but
     // not within keys.
+    if (is_array($value)) {
+      $this->validateKeys($value);
+    }
     $parts = explode('.', $key);
     if (count($parts) == 1) {
       $this->data[$key] = $value;
diff --git a/core/modules/migrate/src/Plugin/migrate/destination/Config.php b/core/modules/migrate/src/Plugin/migrate/destination/Config.php
index f842259..51e1b99 100644
--- a/core/modules/migrate/src/Plugin/migrate/destination/Config.php
+++ b/core/modules/migrate/src/Plugin/migrate/destination/Config.php
@@ -70,7 +70,7 @@ public static function create(ContainerInterface $container, array $configuratio
   public function import(Row $row, array $old_destination_id_values = array()) {
     foreach ($row->getRawDestination() as $key => $value) {
       if (isset($value) || !empty($this->configuration['store null'])) {
-        $this->config->set($key, $value);
+        $this->config->set(str_replace(Row::DESTINATION_PROPERTY_SEPARATOR, '.', $key), $value);
       }
     }
     $this->config->save();
diff --git a/core/modules/migrate/src/Plugin/migrate/destination/EntityConfigBase.php b/core/modules/migrate/src/Plugin/migrate/destination/EntityConfigBase.php
index e788939..5e3c143 100644
--- a/core/modules/migrate/src/Plugin/migrate/destination/EntityConfigBase.php
+++ b/core/modules/migrate/src/Plugin/migrate/destination/EntityConfigBase.php
@@ -75,7 +75,7 @@ public function getIds() {
    */
   protected function updateEntity(EntityInterface $entity, Row $row) {
     foreach ($row->getRawDestination() as $property => $value) {
-      $this->updateEntityProperty($entity, explode('.', $property), $value);
+      $this->updateEntityProperty($entity, explode(Row::DESTINATION_PROPERTY_SEPARATOR, $property), $value);
     }
   }
 
diff --git a/core/modules/migrate/src/Row.php b/core/modules/migrate/src/Row.php
index 60cb02f..d2c2d96 100644
--- a/core/modules/migrate/src/Row.php
+++ b/core/modules/migrate/src/Row.php
@@ -37,6 +37,11 @@ class Row {
   protected $destination = array();
 
   /**
+   * Level separator of destination properties.
+   */
+  const DESTINATION_PROPERTY_SEPARATOR = '/';
+
+  /**
    * The mapping between source and destination identifiers.
    *
    * @var array
@@ -186,7 +191,7 @@ public function freezeSource() {
    *   TRUE if the destination property exists.
    */
   public function hasDestinationProperty($property) {
-    return NestedArray::keyExists($this->destination, explode('.', $property));
+    return NestedArray::keyExists($this->destination, explode($this::DESTINATION_PROPERTY_SEPARATOR, $property));
   }
 
   /**
@@ -199,7 +204,7 @@ public function hasDestinationProperty($property) {
    */
   public function setDestinationProperty($property, $value) {
     $this->rawDestination[$property] = $value;
-    NestedArray::setValue($this->destination, explode('.', $property), $value, TRUE);
+    NestedArray::setValue($this->destination, explode($this::DESTINATION_PROPERTY_SEPARATOR, $property), $value, TRUE);
   }
 
   /**
@@ -238,7 +243,7 @@ public function getRawDestination() {
    *   The destination value.
    */
   public function getDestinationProperty($property) {
-    return NestedArray::getValue($this->destination, explode('.', $property));
+    return NestedArray::getValue($this->destination, explode($this::DESTINATION_PROPERTY_SEPARATOR, $property));
   }
 
   /**
diff --git a/core/modules/migrate/tests/src/RowTest.php b/core/modules/migrate/tests/src/RowTest.php
index c30375c..6ccfd6e 100644
--- a/core/modules/migrate/tests/src/RowTest.php
+++ b/core/modules/migrate/tests/src/RowTest.php
@@ -248,8 +248,8 @@ public function testDestination() {
   public function testMultipleDestination() {
     $row = new Row($this->testValues, $this->testSourceIds);
     // Set some deep nested values.
-    $row->setDestinationProperty('image.alt', 'alt text');
-    $row->setDestinationProperty('image.fid', 3);
+    $row->setDestinationProperty('image/alt', 'alt text');
+    $row->setDestinationProperty('image/fid', 3);
 
     $this->assertTrue($row->hasDestinationProperty('image'));
     $this->assertFalse($row->hasDestinationProperty('alt'));
@@ -258,8 +258,8 @@ public function testMultipleDestination() {
     $destination = $row->getDestination();
     $this->assertEquals('alt text', $destination['image']['alt']);
     $this->assertEquals(3, $destination['image']['fid']);
-    $this->assertEquals('alt text', $row->getDestinationProperty('image.alt'));
-    $this->assertEquals(3, $row->getDestinationProperty('image.fid'));
+    $this->assertEquals('alt text', $row->getDestinationProperty('image/alt'));
+    $this->assertEquals(3, $row->getDestinationProperty('image/fid'));
   }
 
 }
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_aggregator_settings.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_aggregator_settings.yml
index 1240261..edc96ff 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_aggregator_settings.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_aggregator_settings.yml
@@ -15,11 +15,11 @@ process:
   fetcher: aggregator_fetcher
   parser: aggregator_parser
   processors: aggregator_processors
-  'items.allowed_html': aggregator_allowed_html_tags
-  'items.teaser_length': aggregator_teaser_length
-  'items.expire': aggregator_clear
-  'source.list_max': aggregator_summary_items
-  'source.category_selector': aggregator_category_selector
+  'items/allowed_html': aggregator_allowed_html_tags
+  'items/teaser_length': aggregator_teaser_length
+  'items/expire': aggregator_clear
+  'source/list_max': aggregator_summary_items
+  'source/category_selector': aggregator_category_selector
 destination:
   plugin: config
   config_name: aggregator.settings
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_block.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_block.yml
index 4fa9ea7..55448b8 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_block.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_block.yml
@@ -54,8 +54,8 @@ process:
       - delta
       - settings
       - visibility
-  'settings.visibility.request_path.pages': pages
-  'settings.visibility.user_role.roles': roles
+  'settings/visibility/request_path/pages': pages
+  'settings/visibility/user_role/roles': roles
 destination:
   plugin: entity:block
 migration_dependencies:
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_book.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_book.yml
index 03758d5..c67f957 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_book.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_book.yml
@@ -4,9 +4,9 @@ source:
   plugin: d6_book
 process:
   nid: nid
-  book.bid: bid
-  book.weight: weight
-  book.pid:
+  'book/bid': bid
+  'book/weight': weight
+  'book/pid':
     -
       plugin: skip_process_on_empty
       source: plid
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_book_settings.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_book_settings.yml
index 0da3a45..82405a1 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_book_settings.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_book_settings.yml
@@ -8,7 +8,7 @@ source:
     - book_allowed_types
 process:
   child_type: book_child_type
-  'block.navigation.mode': book_block_mode
+  'block/navigation/mode': book_block_mode
   allowed_types: book_allowed_types
 destination:
   plugin: config
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_comment.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_comment.yml
index 34e681e..ea8f2fe 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_comment.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_comment.yml
@@ -38,8 +38,8 @@ process:
   changed: timestamp
   status: status #In D6, published=0. We reverse the value in prepareRow.
   thread: thread
-  'comment_body.value': comment
-  'comment_body.format':
+  'comment_body/value': comment
+  'comment_body/format':
     plugin: migration
     migration: d6_filter_format
     source: format
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_comment_field_instance.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_comment_field_instance.yml
index c7631c2..a39d870 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_comment_field_instance.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_comment_field_instance.yml
@@ -14,13 +14,13 @@ process:
   required: constants.required
 
   bundle: node_type
-  'default_value.0.status': comment
-  'settings.default_mode': comment_default_mode
-  'settings.per_page': comment_default_per_page
-  'settings.anonymous': comment_anonymous
-  'settings.subject': comment_subject_field
-  'settings.form_location': comment_form_location
-  'settings.preview': comment_preview
+  'default_value/0/status': comment
+  'settings/default_mode': comment_default_mode
+  'settings/per_page': comment_default_per_page
+  'settings/anonymous': comment_anonymous
+  'settings/subject': comment_subject_field
+  'settings/form_location': comment_form_location
+  'settings/preview': comment_preview
 destination:
   plugin: entity:field_instance_config
 migration_dependencies:
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_contact_settings.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_contact_settings.yml
index e45dde1..e77d096 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_contact_settings.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_contact_settings.yml
@@ -7,7 +7,7 @@ source:
     - contact_hourly_threshold
 process:
   user_default_enabled: contact_default_status
-  'flood.limit': contact_hourly_threshold
+  'flood/limit': contact_hourly_threshold
   default_category:
     plugin: migration
     migration: d6_contact_category
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_custom_block.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_custom_block.yml
index c7dd4ab..2ff0501 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_custom_block.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_custom_block.yml
@@ -8,11 +8,11 @@ process:
   id: bid
   type: constants.type
   info: info
-  'body.format':
+  'body/format':
     plugin: migration
     migration: d6_filter_format
     source: format
-  'body.value': body
+  'body/value': body
 destination:
   plugin: entity:block_content
 migration_dependencies:
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_date_formats.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_date_formats.yml
index 734149b..f5564ef 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_date_formats.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_date_formats.yml
@@ -14,6 +14,6 @@ process:
       date_format_long: long
       date_format_short: short
       date_format_medium: medium
-  'pattern.php': value
+  pattern: value
 destination:
   plugin: entity:date_format
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_field_formatter_settings.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_field_formatter_settings.yml
index 2d76591..9409eff 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_field_formatter_settings.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_field_formatter_settings.yml
@@ -34,9 +34,9 @@ process:
       index:
         - 1
   field_name: field_name
-  "options.label": label
-  "options.weight": weight
-  "options.type":
+  "options/label": label
+  "options/weight": weight
+  "options/type":
       -
         plugin: static_map
         bypass: true
@@ -164,7 +164,7 @@ process:
             default: string
       -
         plugin: field_type_defaults
-  "options.settings":
+  "options/settings":
     -
       plugin: static_map
       bypass: true
@@ -291,7 +291,7 @@ process:
             trim_length: 600
     -
       plugin: field_formatter_settings_defaults
-  "options.third_party_settings": constants.third_party_settings
+  "options/third_party_settings": constants.third_party_settings
 
 destination:
   plugin: component_entity_display
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_field_instance_widget_settings.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_field_instance_widget_settings.yml
index 9f169e1..833876a 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_field_instance_widget_settings.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_field_instance_widget_settings.yml
@@ -26,8 +26,8 @@ process:
   form_mode: constants.form_mode
   field_name: field_name
   entity_type: constants.entity_type
-  "options.weight": weight
-  "options.type":
+  'options/weight': weight
+  'options/type':
     type:
       plugin: static_map
       bypass: true
@@ -45,13 +45,13 @@ process:
         optionwidgets_onoff: options_onoff
         optionwidgets_buttons: options_buttons
         optionwidgets_select: options_select
-  "options.settings":
+  'options/settings':
     -
       plugin: field_instance_widget_settings
       source:
         - widget_type
         - widget_settings
-  "options.third_party_settings": constants.third_party_settings
+  'options/third_party_settings': constants.third_party_settings
 
 destination:
   plugin: component_entity_form_display
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_file_settings.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_file_settings.yml
index 0b7522e..9c2fc14 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_file_settings.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_file_settings.yml
@@ -7,9 +7,9 @@ source:
     - file_description_length
     - file_icon_directory
 process:
-  'description.type': file_description_type
-  'description.length': file_description_length
-  'icon.directory': file_icon_directory
+  'description/type': file_description_type
+  'description/length': file_description_length
+  'icon/directory': file_icon_directory
 destination:
   plugin: config
   config_name: file.settings
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_forum_settings.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_forum_settings.yml
index b46cca5..66697f3 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_forum_settings.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_forum_settings.yml
@@ -9,11 +9,11 @@ source:
     - forum_block_num_0
     - forum_block_num_1
 process:
-  'block.active.limit': forum_block_num_0
-  'block.new.limit': forum_block_num_1
-  'topics.hot_threshold': forum_hot_topic
-  'topics.page_limit': forum_per_page
-  'topics.order': forum_order
+  'block/active/limit': forum_block_num_0
+  'block/new/limit': forum_block_num_1
+  'topics/hot_threshold': forum_hot_topic
+  'topics/page_limit': forum_per_page
+  'topics/order': forum_order
 destination:
   plugin: config
   config_name: forum.settings
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_locale_settings.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_locale_settings.yml
index f0a4828..76cf234 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_locale_settings.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_locale_settings.yml
@@ -7,7 +7,7 @@ source:
     - locale_js_directory
 process:
   cache_string: locale_cache_strings
-  'javascript.directory': locale_js_directory
+  'javascript/directory': locale_js_directory
 destination:
   plugin: config
   config_name: locale.settings
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_node.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_node.yml
index b74df84..ac9cd36 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_node.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_node.yml
@@ -14,11 +14,11 @@ process:
   changed: changed
   promote: promote
   sticky: sticky
-  body.format:
+  'body/format':
     plugin: migration
     migration: d6_filter_format
     source: format
-  body.value: body
+  'body/value': body
 
 #  unmapped d6 fields.
 #  tnid
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_node_revision.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_node_revision.yml
index 537b255..5010ce9 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_node_revision.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_node_revision.yml
@@ -14,11 +14,11 @@ process:
   changed: changed
   promote: promote
   sticky: sticky
-  body.format:
+  'body/format':
     plugin: migration
     migration: d6_filter_format
     source: format
-  body.value: body
+  'body/value': body
 
 #  unmapped d6 fields.
 #  tnid
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_search_page.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_search_page.yml
index 87e1805..2bddcb5 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_search_page.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_search_page.yml
@@ -17,7 +17,7 @@ process:
   id: constants.id
   path: constants.path
   plugin: constants.plugin
-  configuration.rankings:
+  'configuration/rankings':
     plugin: d6_search_configuration_rankings
 destination:
   plugin: entity:search_page
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_search_settings.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_search_settings.yml
index 00a886e..be1d9ea 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_search_settings.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_search_settings.yml
@@ -9,9 +9,9 @@ source:
     - search_tag_weights
     - search_and_or_limit
 process:
-  'index.minimum_word_size': minimum_word_size
-  'index.overlap_cjk': overlap_cjk
-  'index.cron_limit': search_cron_limit
+  'index/minimum_word_size': minimum_word_size
+  'index/overlap_cjk': overlap_cjk
+  'index/cron_limit': search_cron_limit
 destination:
   plugin: config
   config_name: search.settings
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_simpletest_settings.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_simpletest_settings.yml
index 30b85d9..c6320ea 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_simpletest_settings.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_simpletest_settings.yml
@@ -10,9 +10,9 @@ source:
     - simpletest_verbose
 process:
   clear_results: simpletest_clear_results
-  'httpauth.method': simpletest_httpauth_method
-  'httpauth.password': simpletest_httpauth_password
-  'httpauth.username': simpletest_httpauth_username
+  'httpauth/method': simpletest_httpauth_method
+  'httpauth/password': simpletest_httpauth_password
+  'httpauth/username': simpletest_httpauth_username
   verbose: simpletest_verbose
 destination:
   plugin: config
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_statistics_settings.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_statistics_settings.yml
index 9cc1b9c..66f58cb 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_statistics_settings.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_statistics_settings.yml
@@ -10,12 +10,12 @@ source:
     - statistics_block_top_all_num
     - statistics_block_top_last_num
 process:
-  'access_log.enable': statistics_enable_access_log
-  'access_log.max_lifetime': statistics_flush_accesslog_timer
+  'access_log/enable': statistics_enable_access_log
+  'access_log/max_lifetime': statistics_flush_accesslog_timer
   'count_content_views': statistics_count_content_views
-  'block.popular.top_day_limit': statistics_block_top_day_num
-  'block.popular.top_all_limit': statistics_block_top_all_num
-  'block.popular.top_recent_limit': statistics_block_top_last_num
+  'block/popular/top_day_limit': statistics_block_top_day_num
+  'block/popular/top_all_limit': statistics_block_top_all_num
+  'block/popular/top_recent_limit': statistics_block_top_last_num
 destination:
   plugin: config
   config_name: statistics.settings
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_system_cron.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_system_cron.yml
index 1807732..96d9d16 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_system_cron.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_system_cron.yml
@@ -7,8 +7,8 @@ source:
     - cron_threshold_error
     - cron_last
 process:
-  'threshold.warning': cron_threshold_warning
-  'threshold.error': cron_threshold_error
+  'threshold/warning': cron_threshold_warning
+  'threshold/error': cron_threshold_error
 destination:
   plugin: config
   config_name: system.cron
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_system_file.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_system_file.yml
index 3fdb86f..61777f9 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_system_file.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_system_file.yml
@@ -6,8 +6,8 @@ source:
     - file_directory_path
     - file_directory_temp
 process:
-  'path.private': file_directory_path
-  'path.temporary': file_directory_temp
+  'path/private': file_directory_path
+  'path/temporary': file_directory_temp
 destination:
   plugin: config
   config_name: system.file
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_system_performance.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_system_performance.yml
index 25bf122..a7f94d0 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_system_performance.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_system_performance.yml
@@ -7,9 +7,9 @@ source:
     - preprocess_js
     - cache_lifetime
 process:
-  'css.preprocess': preprocess_css
-  'js.preprocess': preprocess_js
-  'cache.page.max_age': cache_lifetime
+  'css/preprocess': preprocess_css
+  'js/preprocess': preprocess_js
+  'cache/page/max_age': cache_lifetime
 destination:
   plugin: config
   config_name: system.performance
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_system_rss.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_system_rss.yml
index 0325553..1209531 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_system_rss.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_system_rss.yml
@@ -5,7 +5,7 @@ source:
   variables:
     - feed_default_items
 process:
-  'items.limit': feed_default_items
+  'items/limit': feed_default_items
 destination:
   plugin: config
   config_name: system.rss
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_system_site.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_system_site.yml
index f3b5b08..59f6598 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_system_site.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_system_site.yml
@@ -15,9 +15,9 @@ process:
   name: site_name
   mail: site_mail
   slogan: site_slogan
-  'page.front': site_frontpage
-  'page.403': site_403
-  'page.404': site_404
+  'page/front': site_frontpage
+  'page/403': site_403
+  'page/404': site_404
   weight_select_max: drupal_weight_select_max
   admin_compact_mode: admin_compact_mode
 destination:
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_update_settings.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_update_settings.yml
index 5b34a2e..1136986 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_update_settings.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_update_settings.yml
@@ -8,10 +8,10 @@ source:
     - update_notification_threshold
     - update_notify_emails
 process:
-  'fetch.max_attempts': update_max_fetch_attempts
-  'fetch.url': update_fetch_url
-  'notification.threshold': update_notification_threshold
-  'notification.mails': update_notify_emails
+  'fetch/max_attempts': update_max_fetch_attempts
+  'fetch/url': update_fetch_url
+  'notification/threshold': update_notification_threshold
+  'notification/mails': update_notify_emails
 destination:
   plugin: config
   config_name: update.settings
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_upload_entity_display.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_upload_entity_display.yml
index f915411..0d625d1 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_upload_entity_display.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_upload_entity_display.yml
@@ -17,7 +17,7 @@ process:
   field_name: constants.name
   type: constants.type
   options: constants.options
-  'options.type': @type
+  'options/type': @type
 destination:
   plugin: component_entity_display
 migration_dependencies:
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_upload_entity_form_display.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_upload_entity_form_display.yml
index f6d8ef9..c4a1662 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_upload_entity_form_display.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_upload_entity_form_display.yml
@@ -19,7 +19,7 @@ process:
   form_mode: constants.form_mode
   type: constants.type
   options: constants.options
-  'options.type': @type
+  'options/type': @type
 destination:
   plugin: component_entity_form_display
 migration_dependencies:
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_upload_field.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_upload_field.yml
index 05cd8e2..0cf1336 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_upload_field.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_upload_field.yml
@@ -16,6 +16,6 @@ process:
   name: constants.name
   type: constants.type
   cardinality: constants.cardinality
-  settings.display_field: constants.display_field
+  'settings/display_field': constants.display_field
 destination:
   plugin: entity:field_config
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_upload_field_instance.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_upload_field_instance.yml
index 8a85b40..d406e41 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_upload_field_instance.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_upload_field_instance.yml
@@ -12,8 +12,8 @@ process:
   bundle: node_type
   field_name: constants.name
   settings: constants.settings
-  'settings.file_extensions': file_extensions
-  'settings.max_filesize': max_filesize
+  'settings/file_extensions': file_extensions
+  'settings/max_filesize': max_filesize
 destination:
   plugin: entity:field_instance_config
 migration_dependencies:
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_user_mail.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_user_mail.yml
index 9716bef..5f20f17 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_user_mail.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_user_mail.yml
@@ -18,20 +18,20 @@ source:
     - user_mail_status_blocked_subject
     - user_mail_status_blocked_body
 process:
-  'status_activated.subject': user_mail_status_activated_subject
-  'status_activated.body': user_mail_status_activated_body
-  'password_reset.subject': user_mail_password_reset_subject
-  'password_reset.body': user_mail_password_reset_body
-  'cancel_confirm.subject': user_mail_status_deleted_subject
-  'cancel_confirm.body': user_mail_status_deleted_body
-  'register_admin_created.subject': user_mail_register_admin_created_subject
-  'register_admin_created.body': user_mail_register_admin_created_body
-  'register_no_approval_required.subject': user_mail_register_no_approval_required_subject
-  'register_no_approval_required.body': user_mail_register_no_approval_required_body
-  'register_pending_approval.subject': user_mail_user_mail_register_pending_approval_subject
-  'register_pending_approval.body': user_mail_user_mail_register_pending_approval_body
-  'status_blocked.subject': user_mail_status_blocked_subject
-  'status_blocked.body': user_mail_status_blocked_body
+  'status_activated/subject': user_mail_status_activated_subject
+  'status_activated/body': user_mail_status_activated_body
+  'password_reset/subject': user_mail_password_reset_subject
+  'password_reset/body': user_mail_password_reset_body
+  'cancel_confirm/subject': user_mail_status_deleted_subject
+  'cancel_confirm/body': user_mail_status_deleted_body
+  'register_admin_created/subject': user_mail_register_admin_created_subject
+  'register_admin_created/body': user_mail_register_admin_created_body
+  'register_no_approval_required/subject': user_mail_register_no_approval_required_subject
+  'register_no_approval_required/body': user_mail_register_no_approval_required_body
+  'register_pending_approval/subject': user_mail_user_mail_register_pending_approval_subject
+  'register_pending_approval/body': user_mail_user_mail_register_pending_approval_body
+  'status_blocked/subject': user_mail_status_blocked_subject
+  'status_blocked/body': user_mail_status_blocked_body
 destination:
   plugin: config
   config_name: user.mail
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_user_picture_entity_display.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_user_picture_entity_display.yml
index ae74352..c2b6633 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_user_picture_entity_display.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_user_picture_entity_display.yml
@@ -20,7 +20,7 @@ process:
   field_name: constants.name
   type: constants.type
   options: constants.options
-  options.type: @type
+  'options/type': @type
 destination:
   plugin: component_entity_display
 migration_dependencies:
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_user_picture_entity_form_display.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_user_picture_entity_form_display.yml
index a91e2b4..53e5e2c 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_user_picture_entity_form_display.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_user_picture_entity_form_display.yml
@@ -20,7 +20,7 @@ process:
   form_mode: constants.form_mode
   type: constants.type
   options: constants.options
-  options.type: @type
+  'options/type': @type
 destination:
   plugin: component_entity_form_display
 migration_dependencies:
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_user_picture_field_instance.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_user_picture_field_instance.yml
index 22962bf..876ae01 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_user_picture_field_instance.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_user_picture_field_instance.yml
@@ -18,9 +18,9 @@ process:
   bundle: constants.bundle
   field_name: constants.name
   settings: constants.settings
-  'settings.file_directory': file_directory
-  'settings.max_filesize': max_filesize
-  'settings.max_resolution': max_resolution
+  'settings/file_directory': file_directory
+  'settings/max_filesize': max_filesize
+  'settings/max_resolution': max_resolution
 destination:
   plugin: entity:field_instance_config
 migration_dependencies:
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_user_profile_entity_display.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_user_profile_entity_display.yml
index 0e026dc..d608722 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_user_profile_entity_display.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_user_profile_entity_display.yml
@@ -26,7 +26,7 @@ process:
       textarea: text_default
       url: link_default
   options: constants.options
-  'options.type': @type
+  'options/type': @type
   hidden:
     plugin: static_map
     source: visibility
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_user_profile_entity_form_display.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_user_profile_entity_form_display.yml
index 6dc6148..144b081 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_user_profile_entity_form_display.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_user_profile_entity_form_display.yml
@@ -26,13 +26,13 @@ process:
       textarea: text_textarea
       url: link_default
   options: constants.options
-  'options.type': @type
-  'options.settings':
+  'options/type': @type
+  'options/settings':
     plugin: field_instance_widget_settings
     source:
       - @type
       - constants.empty # we don't have any settings.
-  'options.settings.display_label':  # Single on/off checkboxes need to have display_label = true otherwise their label doesn't show.
+  'options/settings/display_label':  # Single on/off checkboxes need to have display_label = true otherwise their label doesn't show.
     plugin: static_map
     default_value: false
     source: type
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_vocabulary_field.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_vocabulary_field.yml
index 13d3bf6..9c2cb88 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_vocabulary_field.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_vocabulary_field.yml
@@ -14,8 +14,8 @@ process:
     plugin: migration
     migration: d6_taxonomy_vocabulary
     source: vid
-  'settings.allowed_values.0.vocabulary': @name
-  'settings.allowed_values.0.parent': constants.parent
+  'settings/allowed_values/0/vocabulary': @name
+  'settings/allowed_values/0/parent': constants.parent
   cardinality: constants.cardinality
 destination:
   plugin: entity:field_config
diff --git a/core/modules/options/config/schema/options.schema.yml b/core/modules/options/config/schema/options.schema.yml
index 8c90839..b81080e 100644
--- a/core/modules/options/config/schema/options.schema.yml
+++ b/core/modules/options/config/schema/options.schema.yml
@@ -8,8 +8,15 @@ field.list_integer.settings:
       type: sequence
       label: 'Allowed values list'
       sequence:
-        - type: string
-          label: 'Value'
+        - type: mapping
+          label: 'Allowed value with label'
+          mapping:
+            value:
+              type: integer
+              label: 'Value'
+            label:
+              type: label
+              label: 'Label'
     allowed_values_function:
       type: string
       label: 'Allowed values function'
@@ -35,8 +42,18 @@ field.list_float.settings:
   label: 'List (float) settings'
   mapping:
     allowed_values:
-      type: ignore
+      type: sequence
       label: 'Allowed values list'
+      sequence:
+        - type: mapping
+          label: 'Allowed value with label'
+          mapping:
+            value:
+              type: float
+              label: 'Value'
+            label:
+              type: label
+              label: 'Label'
     allowed_values_function:
       type: string
       label: 'Allowed values function'
@@ -65,8 +82,15 @@ field.list_text.settings:
       type: sequence
       label: 'Allowed values list'
       sequence:
-        - type: string
-          label: 'Value'
+        - type: mapping
+          label: 'Allowed value with label'
+          mapping:
+            value:
+              type: string
+              label: 'Value'
+            label:
+              type: label
+              label: 'Label'
     allowed_values_function:
       type: string
       label: 'Allowed values function'
@@ -95,8 +119,15 @@ field.list_boolean.settings:
       type: sequence
       label: 'Allowed values list'
       sequence:
-        - type: string
-          label: 'Value'
+        - type: mapping
+          label: 'Allowed value with label'
+          mapping:
+            value:
+              type: boolean
+              label: 'Value'
+            label:
+              type: label
+              label: 'Label'
     allowed_values_function:
       type: string
       label: 'Allowed values function'
diff --git a/core/modules/options/options.module b/core/modules/options/options.module
index d9a1b24..698c719 100644
--- a/core/modules/options/options.module
+++ b/core/modules/options/options.module
@@ -11,6 +11,7 @@
 use Drupal\Core\Entity\Exception\FieldStorageDefinitionUpdateForbiddenException;
 use Drupal\field\FieldConfigInterface;
 use Drupal\field\FieldConfigUpdateForbiddenException;
+use Drupal\options\Plugin\Field\FieldType\ListItemBase;
 
 /**
  * Implements hook_help().
@@ -60,8 +61,9 @@ function options_field_config_delete(FieldConfigInterface $field) {
  *   The entity object.
  *
  * @return
- *   The array of allowed values. Keys of the array are the raw stored values
- *   (number or text), values of the array are the display labels.
+ *   The array of allowed values. Each array element is an associative
+ *   array with 'value' and 'label' keys. The 'value' key stores the raw stored
+ *   value (number or text), the 'label' key stores the display labels.
  */
 function options_allowed_values(FieldDefinitionInterface $field_definition, EntityInterface $entity) {
   $allowed_values = &drupal_static(__FUNCTION__, array());
@@ -99,7 +101,10 @@ function options_field_config_update_forbid(FieldConfigInterface $field, FieldCo
     // Forbid any update that removes allowed values with actual data.
     $allowed_values = $field->getSetting('allowed_values');
     $prior_allowed_values = $prior_field->getSetting('allowed_values');
-    $lost_keys = array_diff(array_keys($prior_allowed_values), array_keys($allowed_values));
+    $lost_keys = array_diff(
+      array_keys(ListItemBase::simplifyAllowedValues($prior_allowed_values)),
+      array_keys(ListItemBase::simplifyAllowedValues($allowed_values))
+    );
     if (_options_values_in_use($field->entity_type, $field->getName(), $lost_keys)) {
       throw new FieldStorageDefinitionUpdateForbiddenException(t('A list field (@field_name) with existing data cannot have its keys changed.', array('@field_name' => $field->getName())));
     }
diff --git a/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php b/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php
index d61aef1..ea1b6e5 100644
--- a/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php
+++ b/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php
@@ -129,8 +129,8 @@ public static function validateAllowedValues($element, &$form_state) {
     }
     else {
       // Check that keys are valid for the field type.
-      foreach ($values as $key => $value) {
-        if ($error = static::validateAllowedValue($key)) {
+      foreach ($values as $item) {
+        if ($error = static::validateAllowedValue($item['value'])) {
           \Drupal::formBuilder()->setError($element, $form_state, $error);
           break;
         }
@@ -138,7 +138,10 @@ public static function validateAllowedValues($element, &$form_state) {
 
       // Prevent removing values currently in use.
       if ($element['#field_has_data']) {
-        $lost_keys = array_diff(array_keys($element['#allowed_values']), array_keys($values));
+        $lost_keys = array_diff(
+          array_keys(static::simplifyAllowedValues($element['#allowed_values'])),
+          array_keys(static::simplifyAllowedValues($values))
+        );
         if (_options_values_in_use($element['#entity_type'], $element['#field_name'], $lost_keys)) {
           \Drupal::formBuilder()->setError($element, $form_state, t('Allowed values list: some values are being removed while currently in use.'));
         }
@@ -193,7 +196,7 @@ protected static function extractAllowedValues($string, $has_data) {
         return;
       }
 
-      $values[$key] = $value;
+      $values[] = array('value' => $key, 'label' => $value);
     }
 
     // We generate keys only if the list contains no explicit key at all.
@@ -205,6 +208,25 @@ protected static function extractAllowedValues($string, $has_data) {
   }
 
   /**
+   * Simplify allowed values to a key-value array from the structured array.
+   *
+   * @param array $structured_values
+   *   Array of items with a 'value' and 'label' key each for the allowed
+   *   values.
+   *
+   * @return array
+   *   Allowed values were the array key is the 'value' value, the value is
+   *   the 'label' value.
+   */
+  public static function simplifyAllowedValues(array $structured_values) {
+    $values = array();
+    foreach ($structured_values as $item) {
+      $values[$item['value']] = $item['label'];
+    }
+    return $values;
+  }
+
+  /**
    * Checks whether a candidate allowed value is valid.
    *
    * @param string $option
@@ -220,19 +242,19 @@ protected static function validateAllowedValue($option) { }
    *
    * This string format is suitable for edition in a textarea.
    *
-   * @param array $values
-   *   An array of values, where array keys are values and array values are
-   *   labels.
+   * @param array $structured_values
+   *   An array of values, where elements are arrays with 'value' and 'label'
+   *   keys.
    *
    * @return string
    *   The string representation of the $values array:
    *    - Values are separated by a carriage return.
-   *    - Each value is in the format "value|label" or "value".
+   *    - Each value is in the format "value|label".
    */
-  protected function allowedValuesString($values) {
+  protected function allowedValuesString($structured_values) {
     $lines = array();
-    foreach ($values as $key => $value) {
-      $lines[] = "$key|$value";
+    foreach ($structured_values as $item) {
+      $lines[] = $item['value'] . '|' . $item['label'];
     }
     return implode("\n", $lines);
   }
diff --git a/core/modules/options/src/Tests/OptionsFieldUITest.php b/core/modules/options/src/Tests/OptionsFieldUITest.php
index baecfca..84f5256 100644
--- a/core/modules/options/src/Tests/OptionsFieldUITest.php
+++ b/core/modules/options/src/Tests/OptionsFieldUITest.php
@@ -60,15 +60,24 @@ function testOptionsAllowedValuesInteger() {
 
     // Flat list of textual values.
     $string = "Zero\nOne";
-    $array = array('0' => 'Zero', '1' => 'One');
+    $array = array(
+      array('value' => '0', 'label' => 'Zero'),
+      array('value' => '1', 'label' => 'One'),
+    );
     $this->assertAllowedValuesInput($string, $array, 'Unkeyed lists are accepted.');
     // Explicit integer keys.
     $string = "0|Zero\n2|Two";
-    $array = array('0' => 'Zero', '2' => 'Two');
+    $array = array(
+      array('value' => '0', 'label' => 'Zero'),
+      array('value' => '2', 'label' => 'Two'),
+    );
     $this->assertAllowedValuesInput($string, $array, 'Integer keys are accepted.');
     // Check that values can be added and removed.
     $string = "0|Zero\n1|One";
-    $array = array('0' => 'Zero', '1' => 'One');
+    $array = array(
+      array('value' => '0', 'label' => 'Zero'),
+      array('value' => '1', 'label' => 'One'),
+    );
     $this->assertAllowedValuesInput($string, $array, 'Values can be added and removed.');
     // Non-integer keys.
     $this->assertAllowedValuesInput("1.1|One", 'keys must be integers', 'Non integer keys are rejected.');
@@ -88,17 +97,26 @@ function testOptionsAllowedValuesInteger() {
 
     // Check that values can be added but values in use cannot be removed.
     $string = "0|Zero\n1|One\n2|Two";
-    $array = array('0' => 'Zero', '1' => 'One', '2' => 'Two');
+    $array = array(
+      array('value' => '0', 'label' => 'Zero'),
+      array('value' => '1', 'label' => 'One'),
+      array('value' => '2', 'label' => 'Two'),
+    );
     $this->assertAllowedValuesInput($string, $array, 'Values can be added.');
     $string = "0|Zero\n1|One";
-    $array = array('0' => 'Zero', '1' => 'One');
+    $array = array(
+      array('value' => '0', 'label' => 'Zero'),
+      array('value' => '1', 'label' => 'One'),
+    );
     $this->assertAllowedValuesInput($string, $array, 'Values not in use can be removed.');
     $this->assertAllowedValuesInput("0|Zero", 'some values are being removed while currently in use', 'Values in use cannot be removed.');
 
     // Delete the node, remove the value.
     $node->delete();
     $string = "0|Zero";
-    $array = array('0' => 'Zero');
+    $array = array(
+      array('value' => '0', 'label' => 'Zero'),
+    );
     $this->assertAllowedValuesInput($string, $array, 'Values not in use can be removed.');
   }
 
@@ -111,15 +129,25 @@ function testOptionsAllowedValuesFloat() {
 
     // Flat list of textual values.
     $string = "Zero\nOne";
-    $array = array('0' => 'Zero', '1' => 'One');
+    $array = array(
+      array('value' => '0', 'label' => 'Zero'),
+      array('value' => '1', 'label' => 'One'),
+    );
     $this->assertAllowedValuesInput($string, $array, 'Unkeyed lists are accepted.');
     // Explicit numeric keys.
     $string = "0|Zero\n.5|Point five";
-    $array = array('0' => 'Zero', '0.5' => 'Point five');
+    $array = array(
+      array('value' => '0', 'label' => 'Zero'),
+      array('value' => '0.5', 'label' => 'Point five'),
+    );
     $this->assertAllowedValuesInput($string, $array, 'Integer keys are accepted.');
     // Check that values can be added and removed.
     $string = "0|Zero\n.5|Point five\n1.0|One";
-    $array = array('0' => 'Zero', '0.5' => 'Point five', '1' => 'One');
+    $array = array(
+      array('value' => '0', 'label' => 'Zero'),
+      array('value' => '0.5', 'label' => 'Point five'),
+      array('value' => '1', 'label' => 'One'),
+    );
     $this->assertAllowedValuesInput($string, $array, 'Values can be added and removed.');
     // Non-numeric keys.
     $this->assertAllowedValuesInput("abc|abc\n", 'each key must be a valid integer or decimal', 'Non numeric keys are rejected.');
@@ -138,17 +166,26 @@ function testOptionsAllowedValuesFloat() {
 
     // Check that values can be added but values in use cannot be removed.
     $string = "0|Zero\n.5|Point five\n2|Two";
-    $array = array('0' => 'Zero', '0.5' => 'Point five', '2' => 'Two');
+    $array = array(
+      array('value' => '0', 'label' => 'Zero'),
+      array('value' => '0.5', 'label' => 'Point five'),
+      array('value' => '2', 'label' => 'Two'),
+    );
     $this->assertAllowedValuesInput($string, $array, 'Values can be added.');
     $string = "0|Zero\n.5|Point five";
-    $array = array('0' => 'Zero', '0.5' => 'Point five');
+    $array = array(
+      array('value' => '0', 'label' => 'Zero'),
+      array('value' => '0.5', 'label' => 'Point five'),
+    );
     $this->assertAllowedValuesInput($string, $array, 'Values not in use can be removed.');
     $this->assertAllowedValuesInput("0|Zero", 'some values are being removed while currently in use', 'Values in use cannot be removed.');
 
     // Delete the node, remove the value.
     $node->delete();
     $string = "0|Zero";
-    $array = array('0' => 'Zero');
+    $array = array(
+      array('value' => '0', 'label' => 'Zero'),
+    );
     $this->assertAllowedValuesInput($string, $array, 'Values not in use can be removed.');
   }
 
@@ -161,19 +198,31 @@ function testOptionsAllowedValuesText() {
 
     // Flat list of textual values.
     $string = "Zero\nOne";
-    $array = array('Zero' => 'Zero', 'One' => 'One');
+    $array = array(
+      array('value' => 'Zero', 'label' => 'Zero'),
+      array('value' => 'One', 'label' => 'One'),
+    );
     $this->assertAllowedValuesInput($string, $array, 'Unkeyed lists are accepted.');
     // Explicit keys.
     $string = "zero|Zero\none|One";
-    $array = array('zero' => 'Zero', 'one' => 'One');
+    $array = array(
+      array('value' => 'zero', 'label' => 'Zero'),
+      array('value' => 'one', 'label' => 'One'),
+    );
     $this->assertAllowedValuesInput($string, $array, 'Explicit keys are accepted.');
     // Check that values can be added and removed.
     $string = "zero|Zero\ntwo|Two";
-    $array = array('zero' => 'Zero', 'two' => 'Two');
+    $array = array(
+      array('value' => 'zero', 'label' => 'Zero'),
+      array('value' => 'two', 'label' => 'Two'),
+    );
     $this->assertAllowedValuesInput($string, $array, 'Values can be added and removed.');
     // Mixed list of keyed and unkeyed values.
     $string = "zero|Zero\nOne\n";
-    $array = array('zero' => 'Zero', 'One' => 'One');
+    $array = array(
+      array('value' => 'zero', 'label' => 'Zero'),
+      array('value' => 'One', 'label' => 'One'),
+    );
     $this->assertAllowedValuesInput($string, $array, 'Mixed lists are accepted.');
     // Overly long keys.
     $this->assertAllowedValuesInput("zero|Zero\n" . $this->randomName(256) . "|One", 'each key must be a string at most 255 characters long', 'Overly long keys are rejected.');
@@ -188,22 +237,34 @@ function testOptionsAllowedValuesText() {
     // Check that flat lists of values are still accepted once the field has
     // data.
     $string = "Zero\nOne";
-    $array = array('Zero' => 'Zero', 'One' => 'One');
+    $array = array(
+      array('value' => 'Zero', 'label' => 'Zero'),
+      array('value' => 'One', 'label' => 'One'),
+    );
     $this->assertAllowedValuesInput($string, $array, 'Unkeyed lists are still accepted once the field has data.');
 
     // Check that values can be added but values in use cannot be removed.
     $string = "Zero\nOne\nTwo";
-    $array = array('Zero' => 'Zero', 'One' => 'One', 'Two' => 'Two');
+    $array = array(
+      array('value' => 'Zero', 'label' => 'Zero'),
+      array('value' => 'One', 'label' => 'One'),
+      array('value' => 'Two', 'label' => 'Two'),
+    );
     $this->assertAllowedValuesInput($string, $array, 'Values can be added.');
     $string = "Zero\nOne";
-    $array = array('Zero' => 'Zero', 'One' => 'One');
+    $array = array(
+      array('value' => 'Zero', 'label' => 'Zero'),
+      array('value' => 'One', 'label' => 'One'),
+    );
     $this->assertAllowedValuesInput($string, $array, 'Values not in use can be removed.');
     $this->assertAllowedValuesInput("Zero", 'some values are being removed while currently in use', 'Values in use cannot be removed.');
 
     // Delete the node, remove the value.
     $node->delete();
     $string = "Zero";
-    $array = array('Zero' => 'Zero');
+    $array = array(
+      array('value' => 'Zero', 'label' => 'Zero'),
+    );
     $this->assertAllowedValuesInput($string, $array, 'Values not in use can be removed.');
   }
 
@@ -244,7 +305,10 @@ function testOptionsTrimmedValuesText() {
 
     // Explicit keys.
     $string = "zero |Zero\none | One";
-    $array = array('zero' => 'Zero', 'one' => 'One');
+    $array = array(
+      array('value' => 'zero', 'label' => 'Zero'),
+      array('value' => 'one', 'label' => 'One'),
+    );
     $this->assertAllowedValuesInput($string, $array, 'Explicit keys are accepted and trimmed.');
   }
 
