diff --git a/core/config/schema/core.data_types.schema.yml b/core/config/schema/core.data_types.schema.yml
index 130d4cc..93743e4 100644
--- a/core/config/schema/core.data_types.schema.yml
+++ b/core/config/schema/core.data_types.schema.yml
@@ -56,6 +56,11 @@ label:
   label: 'Label'
   translatable: true
 
+# String containing plural variants, separated by EXT.
+plural_label:
+  type: label
+  label: 'Plural variants'
+
 # Internal Drupal path
 path:
   type: string
diff --git a/core/modules/config_translation/config_translation.module b/core/modules/config_translation/config_translation.module
index b4f882b..3c81f78 100644
--- a/core/modules/config_translation/config_translation.module
+++ b/core/modules/config_translation/config_translation.module
@@ -188,6 +188,7 @@ function config_translation_config_schema_info_alter(&$definitions) {
     'text_format' => '\Drupal\config_translation\FormElement\TextFormat',
     'mapping' => '\Drupal\config_translation\FormElement\ListElement',
     'sequence' => '\Drupal\config_translation\FormElement\ListElement',
+    'plural_label' => '\Drupal\config_translation\FormElement\PluralVariants',
   );
 
   // Enhance the text and date type definitions with classes to generate proper
diff --git a/core/modules/config_translation/src/FormElement/FormElementBase.php b/core/modules/config_translation/src/FormElement/FormElementBase.php
index e13cc31..7db01e1 100644
--- a/core/modules/config_translation/src/FormElement/FormElementBase.php
+++ b/core/modules/config_translation/src/FormElement/FormElementBase.php
@@ -91,7 +91,6 @@ public function getTranslationBuild(LanguageInterface $source_language, Language
    *   A render array for the source value.
    */
   protected function getSourceElement(LanguageInterface $source_language, $source_config) {
-    // @todo Should support singular+plurals https://www.drupal.org/node/2454829
     if ($source_config) {
       $value = '<span lang="' . $source_language->getId() . '">' . nl2br($source_config) . '</span>';
     }
@@ -162,7 +161,6 @@ protected function getSourceElement(LanguageInterface $source_language, $source_
    */
   protected function getTranslationElement(LanguageInterface $translation_language, $source_config, $translation_config) {
     // Add basic properties that apply to all form elements.
-    // @todo Should support singular+plurals https://www.drupal.org/node/2454829
     return array(
       '#title' => $this->t('!label <span class="visually-hidden">(!source_language)</span>', array(
         '!label' => $this->t($this->definition['label']),
diff --git a/core/modules/config_translation/src/FormElement/PluralVariants.php b/core/modules/config_translation/src/FormElement/PluralVariants.php
new file mode 100644
index 0000000..a71d8fc
--- /dev/null
+++ b/core/modules/config_translation/src/FormElement/PluralVariants.php
@@ -0,0 +1,82 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\config_translation\FormElement\PluralVariants.
+ */
+
+namespace Drupal\config_translation\FormElement;
+
+use Drupal\Component\Utility\SafeMarkup;
+use Drupal\Core\Config\Config;
+use Drupal\Core\Language\LanguageInterface;
+use Drupal\language\Config\LanguageConfigOverride;
+
+/**
+ * Defines form elements for plurals in configuration translation.
+ */
+class PluralVariants extends FormElementBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getSourceElement(LanguageInterface $source_language, $source_config) {
+    $plurals = $this->getNumberOfPlurals($source_language->getId());
+    $values = explode(LOCALE_PLURAL_DELIMITER, $source_config);
+    $element = array(
+      '#type' => 'fieldset',
+      '#title' => $this->t($this->definition->getLabel()),
+      '#tree' => TRUE,
+    );
+    for ($i = 0; $i < $plurals; $i++) {
+      $element[] = array(
+        '#type' => 'item',
+        '#title' => SafeMarkup::format('@label <span class="visually-hidden">(@source_language)</span>', array(
+          // @todo Should use better labels https://www.drupal.org/node/2499639
+          '@label' => $i == 0 ? $this->t('Singular form') : $this->formatPlural($i, 'First plural form', '@count. plural form'),
+          '@source_language' => $source_language->getName(),
+        )),
+        '#markup' => SafeMarkup::format('<span lang="@lancode">@value</span>', array(
+          '@langcode' => $source_language->getId(),
+          '@value' => isset($values[$i]) ? $values[$i] : $this->t('(Empty)'),
+        )),
+      );
+    }
+    return $element;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getTranslationElement(LanguageInterface $translation_language, $source_config, $translation_config) {
+    $plurals = $this->getNumberOfPlurals($translation_language->getId());
+    $values = explode(LOCALE_PLURAL_DELIMITER, $translation_config);
+    $element = array(
+      '#type' => 'fieldset',
+      '#title' => $this->t($this->definition->getLabel()),
+      '#tree' => TRUE,
+    );
+    for ($i = 0; $i < $plurals; $i++) {
+      $element[] = array(
+        '#type' => 'textfield',
+        '#title' => SafeMarkup::format('@label <span class="visually-hidden">(@translation_language)</span>', array(
+          // @todo Should use better labels https://www.drupal.org/node/2499639
+          '@label' => $i == 0 ? $this->t('Singular form') : $this->formatPlural($i, 'First plural form', '@count. plural form'),
+          '@translation_language' => $translation_language->getName(),
+        )),
+        '#default_value' => isset($values[$i]) ? $values[$i] : '',
+        '#attributes' => array('lang' => $translation_language->getId()),
+      );
+    }
+    return $element;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setConfig(Config $base_config, LanguageConfigOverride $config_translation, $config_values, $base_key = NULL) {
+    $config_values = implode(LOCALE_PLURAL_DELIMITER, $config_values);
+    parent::setConfig($base_config, $config_translation, $config_values, $base_key);
+  }
+
+}
diff --git a/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php b/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php
index c7218df..4bbb408 100644
--- a/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php
+++ b/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php
@@ -89,6 +89,7 @@ protected function setUp() {
         'administer themes',
         'bypass node access',
         'administer content types',
+        'translate interface',
       ]
     );
     // Create and login user.
@@ -610,6 +611,96 @@ public function testViewsTranslationUI() {
   }
 
   /**
+   * Test the number of source elements for plural strings in config translation forms.
+   */
+  public function testPluralConfigStringsSourceElements() {
+    $this->drupalLogin($this->adminUser);
+
+    // Languages to test, with various number of plural forms.
+    $languages = array(
+      'vi' => array('plurals' => 1, 'expected' => array(TRUE, FALSE, FALSE, FALSE)),
+      'fr' => array('plurals' => 2, 'expected' => array(TRUE, TRUE, FALSE, FALSE)),
+      'sl' => array('plurals' => 4, 'expected' => array(TRUE, TRUE, TRUE, TRUE)),
+    );
+
+    foreach ($languages as $langcode => $data) {
+      // Import a .po file to add a new language with a given number of plural forms
+      $name = tempnam('temporary://', $langcode . '_') . '.po';
+      file_put_contents($name, $this->getPoFile($data['plurals']));
+      $this->drupalPostForm('admin/config/regional/translate/import', array(
+        'langcode' => $langcode,
+        'files[file]' => $name,
+      ), t('Import'));
+
+      // Change the config langcode of the 'files' view.
+      $config = \Drupal::service('config.factory')->getEditable('views.view.files');
+      $config->set('langcode', $langcode);
+      $config->save();
+
+      // Go to the translation page of the 'files' view.
+      $translation_url = 'admin/structure/views/view/files/translate/' . $langcode . '/add';
+      $this->drupalGet($translation_url);
+
+      // Check if the expected number of source elements are present.
+      foreach ($data['expected'] as $index => $expected) {
+        if ($expected) {
+          $this->assertRaw('edit-source-config-names-viewsviewfiles-display-default-display-options-fields-count-format-plural-string-' . $index);
+        }
+        else {
+          $this->assertNoRaw('edit-source-config-names-viewsviewfiles-display-default-display-options-fields-count-format-plural-string-' . $index);
+        }
+      }
+    }
+  }
+
+  /**
+   * Test translation of plural strings with multiple plural forms in config.
+   */
+  public function testPluralConfigStrings() {
+    $this->drupalLogin($this->adminUser);
+
+    // First import a .po file with multiple plural forms.
+    // This will also automatically add the 'sl' language.
+    $name = tempnam('temporary://', "sl_") . '.po';
+    file_put_contents($name, $this->getPoFile(4));
+    $this->drupalPostForm('admin/config/regional/translate/import', array(
+      'langcode' => 'sl',
+      'files[file]' => $name,
+    ), t('Import'));
+
+    // Translate the files view, as this one uses numeric formatters.
+    $description = 'Singular form';
+    $field_value = '1 place';
+    $field_value_plural = '@count places';
+    $translation_url = 'admin/structure/views/view/files/translate/sl/add';
+    $this->drupalGet($translation_url);
+
+    // Make sure original text is present on this page, in addition to 2 new
+    // empty fields.
+    $this->assertRaw($description);
+    $this->assertFieldByName('translation[config_names][views.view.files][display][default][display_options][fields][count][format_plural_string][0]', $field_value);
+    $this->assertFieldByName('translation[config_names][views.view.files][display][default][display_options][fields][count][format_plural_string][1]', $field_value_plural);
+    $this->assertFieldByName('translation[config_names][views.view.files][display][default][display_options][fields][count][format_plural_string][2]', '');
+    $this->assertFieldByName('translation[config_names][views.view.files][display][default][display_options][fields][count][format_plural_string][3]', '');
+
+    // Then make sure it also works.
+    $edit = [
+      'translation[config_names][views.view.files][display][default][display_options][fields][count][format_plural_string][0]' => $field_value . ' SL',
+      'translation[config_names][views.view.files][display][default][display_options][fields][count][format_plural_string][1]' => $field_value_plural . ' 1 SL',
+      'translation[config_names][views.view.files][display][default][display_options][fields][count][format_plural_string][2]' => $field_value_plural . ' 2 SL',
+      'translation[config_names][views.view.files][display][default][display_options][fields][count][format_plural_string][3]' => $field_value_plural . ' 3 SL',
+    ];
+    $this->drupalPostForm($translation_url, $edit, t('Save translation'));
+
+    // Make sure the values have changed.
+    $this->drupalGet($translation_url);
+    $this->assertFieldByName('translation[config_names][views.view.files][display][default][display_options][fields][count][format_plural_string][0]', "$field_value SL");
+    $this->assertFieldByName('translation[config_names][views.view.files][display][default][display_options][fields][count][format_plural_string][1]', "$field_value_plural 1 SL");
+    $this->assertFieldByName('translation[config_names][views.view.files][display][default][display_options][fields][count][format_plural_string][2]', "$field_value_plural 2 SL");
+    $this->assertFieldByName('translation[config_names][views.view.files][display][default][display_options][fields][count][format_plural_string][3]', "$field_value_plural 3 SL");
+  }
+
+  /**
    * Test translation storage in locale storage.
    */
   public function testLocaleDBStorage() {
@@ -936,4 +1027,43 @@ protected function assertDisabledTextarea($id) {
     )));
   }
 
+  /**
+   * Helper function that returns a .po file with a given number of plural forms.
+   */
+  public function getPoFile($plurals) {
+    $po_file = array();
+
+    $po_file[1] = <<< EOF
+msgid ""
+msgstr ""
+"Project-Id-Version: Drupal 8\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=UTF-8\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=1; plural=0;\\n"
+EOF;
+
+    $po_file[2] = <<< EOF
+msgid ""
+msgstr ""
+"Project-Id-Version: Drupal 8\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=UTF-8\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=2; plural=(n>1);\\n"
+EOF;
+
+    $po_file[4] = <<< EOF
+msgid ""
+msgstr ""
+"Project-Id-Version: Drupal 8\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=UTF-8\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=4; plural=(((n%100)==1)?(0):(((n%100)==2)?(1):((((n%100)==3)||((n%100)==4))?(2):3)));\\n"
+EOF;
+
+    return $po_file[$plurals];
+  }
+
 }
diff --git a/core/modules/locale/src/Form/TranslateEditForm.php b/core/modules/locale/src/Form/TranslateEditForm.php
index 44e86e7..bac65c7 100644
--- a/core/modules/locale/src/Form/TranslateEditForm.php
+++ b/core/modules/locale/src/Form/TranslateEditForm.php
@@ -123,6 +123,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
           for ($i = 0; $i < $plurals; $i++) {
             $form['strings'][$string->lid]['translations'][$i] = array(
               '#type' => 'textarea',
+              // @todo Should use better labels https://www.drupal.org/node/2499639
               '#title' => ($i == 0 ? $this->t('Singular form') : $this->formatPlural($i, 'First plural form', '@count. plural form')),
               '#rows' => $rows,
               '#default_value' => isset($translation_array[$i]) ? $translation_array[$i] : '',
diff --git a/core/modules/views/config/schema/views.field.schema.yml b/core/modules/views/config/schema/views.field.schema.yml
index 1c884fb..58d4c0d 100644
--- a/core/modules/views/config/schema/views.field.schema.yml
+++ b/core/modules/views/config/schema/views.field.schema.yml
@@ -117,8 +117,8 @@ views.field.numeric:
       type: boolean
       label: 'Format plural'
     format_plural_string:
-      type: label
-      label: 'Singular and one or more plurals'
+      type: plural_label
+      label: 'Plural variants'
     prefix:
       type: label
       label: 'Prefix'
diff --git a/core/modules/views/src/Plugin/views/field/NumericField.php b/core/modules/views/src/Plugin/views/field/NumericField.php
index 70622d1..999a648 100644
--- a/core/modules/views/src/Plugin/views/field/NumericField.php
+++ b/core/modules/views/src/Plugin/views/field/NumericField.php
@@ -102,6 +102,7 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     for ($i = 0; $i < $plurals; $i++) {
       $form['format_plural_values'][$i] = array(
         '#type' => 'textfield',
+        // @todo Should use better labels https://www.drupal.org/node/2499639
         '#title' => ($i == 0 ? $this->t('Singular form') : $this->formatPlural($i, 'First plural form', '@count. plural form')),
         '#default_value' => isset($plural_array[$i]) ? $plural_array[$i] : '',
         '#description' => $this->t('Text to use for this variant, @count will be replaced with the value.'),
