diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/LanguageItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/LanguageItem.php
index b7ce7fb..df09efe 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/LanguageItem.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/LanguageItem.php
@@ -44,7 +44,6 @@ class LanguageItem extends FieldItemBase {
   public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
     $properties['value'] = DataDefinition::create('string')
       ->setLabel(t('Language code'))
-      ->setSetting('is_ascii', TRUE)
       ->setRequired(TRUE);
 
     $properties['language'] = DataReferenceDefinition::create('language')
@@ -74,9 +73,8 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
     return array(
       'columns' => array(
         'value' => array(
-          'type' => 'varchar',
+          'type' => 'varchar_ascii',
           'length' => 12,
-          'is_ascii' => TRUE,
         ),
       ),
     );
diff --git a/core/modules/options/src/Tests/OptionsWidgetsTest.php b/core/modules/options/src/Tests/OptionsWidgetsTest.php
index 6bd4714..24866bd 100644
--- a/core/modules/options/src/Tests/OptionsWidgetsTest.php
+++ b/core/modules/options/src/Tests/OptionsWidgetsTest.php
@@ -72,7 +72,7 @@ protected function setUp() {
           // Make sure that 0 works as an option.
           0 => 'Zero',
           1 => 'One',
-          // Make sure that option text is properly sanitized.
+          // Make sure that option text is properly escaped.
           2 => 'Some <script>dangerous</script> & unescaped <strong>markup</strong>',
         ],
       ],
@@ -112,8 +112,9 @@ function testRadioButtons() {
     $this->assertNoFieldChecked('edit-card-1-0');
     $this->assertNoFieldChecked('edit-card-1-1');
     $this->assertNoFieldChecked('edit-card-1-2');
-    $this->assertRaw('Some dangerous &amp; unescaped <strong>markup</strong>', 'Option text was properly filtered.');
-    $this->assertRaw('Some HTML encoded markup with &lt; &amp; &gt;');
+    $this->assertRaw('Some &lt;script&gt;dangerous&lt;/script&gt; &amp; unescaped &lt;strong&gt;markup&lt;/strong&gt;', 'Option text was properly escaped.');
+    // Test that the output is HTML escaped.
+    $this->assertRaw('Some HTML encoded markup with &lt; &amp;amp; &gt;');
 
     // Select first option.
     $edit = array('card_1' => 0);
@@ -169,7 +170,7 @@ function testCheckBoxes() {
     $this->assertNoFieldChecked('edit-card-2-0');
     $this->assertNoFieldChecked('edit-card-2-1');
     $this->assertNoFieldChecked('edit-card-2-2');
-    $this->assertRaw('Some dangerous &amp; unescaped <strong>markup</strong>', 'Option text was properly filtered.');
+    $this->assertRaw('Some &lt;script&gt;dangerous&lt;/script&gt; &amp; unescaped &lt;strong&gt;markup&lt;/strong&gt;', 'Option text was properly escaped.');
 
     // Submit form: select first and third options.
     $edit = array(
@@ -264,7 +265,7 @@ function testSelectListSingle() {
     $this->assertNoOptionSelected('edit-card-1', 0);
     $this->assertNoOptionSelected('edit-card-1', 1);
     $this->assertNoOptionSelected('edit-card-1', 2);
-    $this->assertRaw('Some dangerous &amp; unescaped markup', 'Option text was properly filtered.');
+    $this->assertRaw('Some &lt;script&gt;dangerous&lt;/script&gt; &amp; unescaped &lt;strong&gt;markup&lt;/strong&gt;', 'Option text was properly escaped.');
 
     // Submit form: select invalid 'none' option.
     $edit = array('card_1' => '_none');
@@ -308,8 +309,7 @@ function testSelectListSingle() {
     $this->assertNoOptionSelected('edit-card-1', 0);
     $this->assertNoOptionSelected('edit-card-1', 1);
     $this->assertNoOptionSelected('edit-card-1', 2);
-    $this->assertRaw('Some dangerous &amp; unescaped markup', 'Option text was properly filtered.');
-    $this->assertRaw('More &lt;script&gt;dangerous&lt;/script&gt; markup', 'Option group text was properly filtered.');
+    $this->assertRaw('Some &lt;script&gt;dangerous&lt;/script&gt; &amp; unescaped &lt;strong&gt;markup&lt;/strong&gt;', 'Option text was properly escaped.');
     $this->assertRaw('Group 1', 'Option groups are displayed.');
 
     // Submit form: select first option.
@@ -359,7 +359,7 @@ function testSelectListMultiple() {
     $this->assertNoOptionSelected('edit-card-2', 0);
     $this->assertNoOptionSelected('edit-card-2', 1);
     $this->assertNoOptionSelected('edit-card-2', 2);
-    $this->assertRaw('Some dangerous &amp; unescaped markup', 'Option text was properly filtered.');
+    $this->assertRaw('Some &lt;script&gt;dangerous&lt;/script&gt; &amp; unescaped &lt;strong&gt;markup&lt;/strong&gt;', 'Option text was properly escaped.');
 
     // Submit form: select first and third options.
     $edit = array('card_2[]' => array(0 => 0, 2 => 2));
@@ -429,8 +429,7 @@ function testSelectListMultiple() {
     $this->assertNoOptionSelected('edit-card-2', 0);
     $this->assertNoOptionSelected('edit-card-2', 1);
     $this->assertNoOptionSelected('edit-card-2', 2);
-    $this->assertRaw('Some dangerous &amp; unescaped markup', 'Option text was properly filtered.');
-    $this->assertRaw('More &lt;script&gt;dangerous&lt;/script&gt; markup', 'Option group text was properly filtered.');
+    $this->assertRaw('Some &lt;script&gt;dangerous&lt;/script&gt; &amp; unescaped &lt;strong&gt;markup&lt;/strong&gt;', 'Option text was properly escaped.');
     $this->assertRaw('Group 1', 'Option groups are displayed.');
 
     // Submit form: select first option.
diff --git a/core/modules/system/src/Tests/Entity/Update/LangcodeToAsciiUpdateTest.php b/core/modules/system/src/Tests/Entity/Update/LangcodeToAsciiUpdateTest.php
new file mode 100644
index 0000000..73c840b
--- /dev/null
+++ b/core/modules/system/src/Tests/Entity/Update/LangcodeToAsciiUpdateTest.php
@@ -0,0 +1,79 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\Tests\Entity\Update\LangcodeToAsciiUpdateTest.
+ */
+
+namespace Drupal\system\Tests\Entity\Update;
+
+use Drupal\Core\Database\Database;
+use Drupal\system\Tests\Update\UpdatePathTestBase;
+
+/**
+ * Tests that the entity langcode fields have been updated to varchar_ascii.
+ *
+ * @group Entity
+ */
+class LangcodeToAsciiUpdateTest extends UpdatePathTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setDatabaseDumpFiles() {
+    $this->databaseDumpFiles = [
+      __DIR__ . '/../../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
+    ];
+  }
+
+  /**
+   * Tests that the column collation has been updated on MySQL.
+   */
+  public function testLangcodeColumnCollation() {
+    // Only testable on MySQL.
+    // @see https://www.drupal.org/node/301038
+    if (Database::getConnection()->databaseType() !== 'mysql') {
+      $this->pass('This test can only run on MySQL');
+      return;
+    }
+
+    // Check a few different tables.
+    $tables = [
+      'node_field_data' => ['langcode'],
+      'users_field_data' => ['langcode', 'preferred_langcode', 'preferred_admin_langcode'],
+    ];
+    foreach ($tables as $table => $columns) {
+      foreach ($columns as $column) {
+        $this->assertEqual('utf8mb4_general_ci', $this->getColumnCollation($table, $column), 'Found correct starting collation for ' . $table . '.' . $column);
+      }
+    }
+
+    // Apply updates.
+    $this->runUpdates();
+
+    foreach ($tables as $table => $columns) {
+      foreach ($columns as $column) {
+        $this->assertEqual('ascii_general_ci', $this->getColumnCollation($table, $column), 'Found correct updated collation for ' . $table . '.' . $column);
+      }
+    }
+  }
+
+  /**
+   * Determine the column collation.
+   *
+   * @param string $table
+   *   The table name.
+   * @param string $column
+   *   The column name.
+   */
+  protected function getColumnCollation($table, $column) {
+    $query = Database::getConnection()->query("SHOW FULL COLUMNS FROM {" . $table . "}");
+    while ($row = $query->fetchAssoc()) {
+      if ($row['Field'] === $column) {
+        return $row['Collation'];
+      }
+    }
+    $this->fail('No collation found for ' . $table . '.' . $column);
+  }
+
+}
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index 0170487..4873b23 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -1463,5 +1463,60 @@ function _system_update_create_block($name, $theme_name, array $values) {
 }
 
 /**
+ * Set langcode fields to be ASCII-only.
+ */
+function system_update_8006() {
+  $database = \Drupal::database();
+  $database_schema = $database->schema();
+
+  $schema = \Drupal::keyValue('entity.storage_schema.sql')->getAll();
+  $schema_copy = $schema;
+  foreach ($schema as $item_name => $item) {
+    foreach ($item as $table_name => $table_schema) {
+      foreach ($table_schema as $schema_key => $schema_data) {
+        if ($schema_key == 'fields') {
+          foreach ($schema_data as $field_name => $field_data) {
+            foreach ($field_data as $field_data_property => $field_data_value) {
+              // Langcode fields have the property 'is_ascii' set, instead
+              // they should have set the type to 'varchar_ascii'.
+              if ($field_data_property == 'is_ascii') {
+                unset($schema_copy[$item_name][$table_name]['fields'][$field_name]['is_ascii']);
+                $schema_copy[$item_name][$table_name]['fields'][$field_name]['type'] = 'varchar_ascii';
+                if ($database->driver() == 'mysql') {
+                  $database_schema->changeField($table_name, $field_name, $field_name, $schema_copy[$item_name][$table_name]['fields'][$field_name]);
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  \Drupal::keyValue('entity.storage_schema.sql')->setMultiple($schema_copy);
+
+  $definitions = \Drupal::keyValue('entity.definitions.installed')->getAll();
+  $definitions_copy = $definitions;
+  foreach ($definitions as $item_name => $item_value) {
+    $suffix = '.field_storage_definitions';
+    if (substr($item_name, -strlen($suffix)) == $suffix) {
+      foreach ($item_value as $field_name => $field_definition) {
+        $reflection = new \ReflectionObject($field_definition);
+        $schema_property = $reflection->getProperty('schema');
+        $schema_property->setAccessible(TRUE);
+        $schema = $schema_property->getValue($field_definition);
+        if (isset($schema['columns']['value']['is_ascii'])) {
+          $schema['columns']['value']['type'] = 'varchar_ascii';
+          unset($schema['columns']['value']['is_ascii']);
+        }
+        $schema_property->setValue($field_definition, $schema);
+        $schema_property->setAccessible(FALSE);
+        $definitions_copy[$item_name][$field_name] = $field_definition;
+      }
+    }
+  }
+  \Drupal::keyValue('entity.definitions.installed')->setMultiple($definitions_copy);
+}
+
+/**
  * @} End of "addtogroup updates-8.0.0-beta".
  */
