diff --git a/includes/form.inc b/includes/form.inc
index e749239..8060224 100644
--- a/includes/form.inc
+++ b/includes/form.inc
@@ -2985,9 +2985,9 @@ function theme_radios($variables) {
   if (isset($element['#id'])) {
     $attributes['id'] = $element['#id'];
   }
-  $attributes['class'] = 'form-radios';
+  $attributes['class'] = array('form-radios');
   if (!empty($element['#attributes']['class'])) {
-    $attributes['class'] .= ' ' . implode(' ', $element['#attributes']['class']);
+    $attributes['class'] = array_merge($attributes['class'], $element['#attributes']['class']);
   }
   if (isset($element['#attributes']['title'])) {
     $attributes['title'] = $element['#attributes']['title'];
@@ -4209,7 +4209,7 @@ function theme_form_element($variables) {
   // This function is invoked as theme wrapper, but the rendered form element
   // may not necessarily have been processed by form_builder().
   $element += array(
-    '#title_display' => 'before',
+    '#title_classes_array' => array(),
   );
 
   // Add element #id for #type 'item'.
@@ -4228,8 +4228,17 @@ function theme_form_element($variables) {
   if (!empty($element['#attributes']['disabled'])) {
     $attributes['class'][] = 'form-disabled';
   }
+  // Add classes specified in the element's #attributes.
+  if (!empty($element['#attributes']['class'])) {
+    $attributes['class'] = array_merge($attributes['class'], $element['#attributes']['class']);
+  }
   $output = '<div' . drupal_attributes($attributes) . '>' . "\n";
 
+  // Prevent form field class inheriting to label in theme_form_element_label()
+  // and allow custom label classes.
+  $variables_title = $variables;
+  $variables_title['element']['#attributes']['class'] = $element['#title_classes_array'];
+
   // If #title is not set, we don't display any label or required marker.
   if (!isset($element['#title'])) {
     $element['#title_display'] = 'none';
@@ -4240,13 +4249,13 @@ function theme_form_element($variables) {
   switch ($element['#title_display']) {
     case 'before':
     case 'invisible':
-      $output .= ' ' . theme('form_element_label', $variables);
+      $output .= ' ' . theme('form_element_label', $variables_title);
       $output .= ' ' . $prefix . $element['#children'] . $suffix . "\n";
       break;
 
     case 'after':
       $output .= ' ' . $prefix . $element['#children'] . $suffix;
-      $output .= ' ' . theme('form_element_label', $variables) . "\n";
+      $output .= ' ' . theme('form_element_label', $variables_title) . "\n";
       break;
 
     case 'none':
@@ -4322,19 +4331,23 @@ function theme_form_element_label($variables) {
 
   $title = filter_xss_admin($element['#title']);
 
-  $attributes = array();
+  $attributes = array('class' => array('form-label'));
   // Style the label as class option to display inline with the element.
   if ($element['#title_display'] == 'after') {
-    $attributes['class'] = 'option';
+    $attributes['class'][] = 'option';
   }
   // Show label only to screen readers to avoid disruption in visual flows.
   elseif ($element['#title_display'] == 'invisible') {
-    $attributes['class'] = 'element-invisible';
+    $attributes['class'][] = 'element-invisible';
   }
 
   if (!empty($element['#id'])) {
     $attributes['for'] = $element['#id'];
   }
+  // Add classes specified in the element's #attributes.
+  if (!empty($element['#attributes']['class'])) {
+    $attributes['class'] = array_merge($attributes['class'], $element['#attributes']['class']);
+  }
 
   // The leading whitespace helps visually separate fields from inline labels.
   return ' <label' . drupal_attributes($attributes) . '>' . $t('!title !required', array('!title' => $title, '!required' => $required)) . "</label>\n";
diff --git a/modules/simpletest/tests/form.test b/modules/simpletest/tests/form.test
index a441cee..50c3286 100644
--- a/modules/simpletest/tests/form.test
+++ b/modules/simpletest/tests/form.test
@@ -778,23 +778,23 @@ class FormsElementsLabelsTestCase extends DrupalWebTestCase {
 
     // Check that the checkbox/radio processing is not interfering with
     // basic placement.
-    $elements = $this->xpath('//input[@id="edit-form-checkboxes-test-third-checkbox"]/following-sibling::label[@for="edit-form-checkboxes-test-third-checkbox" and @class="option"]');
+    $elements = $this->xpath('//input[@id="edit-form-checkboxes-test-third-checkbox"]/following-sibling::label[@for="edit-form-checkboxes-test-third-checkbox" and contains(@class, "option")]');
     $this->assertTrue(isset($elements[0]), "Label follows field and label option class correct for regular checkboxes.");
 
     // Make sure the label is rendered for checkboxes.
-    $elements = $this->xpath('//input[@id="edit-form-checkboxes-test-0"]/following-sibling::label[@for="edit-form-checkboxes-test-0" and @class="option"]');
+    $elements = $this->xpath('//input[@id="edit-form-checkboxes-test-0"]/following-sibling::label[@for="edit-form-checkboxes-test-0" and contains(@class, "option")]');
     $this->assertTrue(isset($elements[0]), "Label 0 found checkbox.");
 
-    $elements = $this->xpath('//input[@id="edit-form-radios-test-second-radio"]/following-sibling::label[@for="edit-form-radios-test-second-radio" and @class="option"]');
+    $elements = $this->xpath('//input[@id="edit-form-radios-test-second-radio"]/following-sibling::label[@for="edit-form-radios-test-second-radio" and contains(@class, "option")]');
     $this->assertTrue(isset($elements[0]), "Label follows field and label option class correct for regular radios.");
 
     // Make sure the label is rendered for radios.
-    $elements = $this->xpath('//input[@id="edit-form-radios-test-0"]/following-sibling::label[@for="edit-form-radios-test-0" and @class="option"]');
+    $elements = $this->xpath('//input[@id="edit-form-radios-test-0"]/following-sibling::label[@for="edit-form-radios-test-0" and contains(@class, "option")]');
     $this->assertTrue(isset($elements[0]), "Label 0 found radios.");
 
     // Exercise various defaults for checkboxes and modifications to ensure
     // appropriate override and correct behavior.
-    $elements = $this->xpath('//input[@id="edit-form-checkbox-test"]/following-sibling::label[@for="edit-form-checkbox-test" and @class="option"]');
+    $elements = $this->xpath('//input[@id="edit-form-checkbox-test"]/following-sibling::label[@for="edit-form-checkbox-test" and contains(@class, "option")]');
     $this->assertTrue(isset($elements[0]), "Label follows field and label option class correct for a checkbox by default.");
 
     // Exercise various defaults for textboxes and modifications to ensure
@@ -805,13 +805,13 @@ class FormsElementsLabelsTestCase extends DrupalWebTestCase {
     $elements = $this->xpath('//input[@id="edit-form-textfield-test-no-title-required"]/preceding-sibling::label[@for="edit-form-textfield-test-no-title-required"]/span[@class="form-required"]');
     $this->assertTrue(isset($elements[0]), "Label tag with required marker precedes required textfield with no title.");
 
-    $elements = $this->xpath('//input[@id="edit-form-textfield-test-title-invisible"]/preceding-sibling::label[@for="edit-form-textfield-test-title-invisible" and @class="element-invisible"]');
+    $elements = $this->xpath('//input[@id="edit-form-textfield-test-title-invisible"]/preceding-sibling::label[@for="edit-form-textfield-test-title-invisible" and contains(@class, "element-invisible")]');
     $this->assertTrue(isset($elements[0]), "Label preceding field and label class is element-invisible.");
 
     $elements = $this->xpath('//input[@id="edit-form-textfield-test-title"]/preceding-sibling::span[@class="form-required"]');
     $this->assertFalse(isset($elements[0]), "No required marker on non-required field.");
 
-    $elements = $this->xpath('//input[@id="edit-form-textfield-test-title-after"]/following-sibling::label[@for="edit-form-textfield-test-title-after" and @class="option"]');
+    $elements = $this->xpath('//input[@id="edit-form-textfield-test-title-after"]/following-sibling::label[@for="edit-form-textfield-test-title-after" and contains(@class, "option")]');
     $this->assertTrue(isset($elements[0]), "Label after field and label option class correct for text field.");
 
     $elements = $this->xpath('//label[@for="edit-form-textfield-test-title-no-show"]');
diff --git a/modules/user/user-rtl.css b/modules/user/user-rtl.css
index 642c943..cdc6df2 100644
--- a/modules/user/user-rtl.css
+++ b/modules/user/user-rtl.css
@@ -19,7 +19,7 @@
 .password-strength-text {
   float: left;
 }
-div.password-confirm {
+div.password-confirm-title {
   float: left;
 }
 .confirm-parent,
diff --git a/modules/user/user.css b/modules/user/user.css
index 079ec38..70f20aa 100644
--- a/modules/user/user.css
+++ b/modules/user/user.css
@@ -56,7 +56,7 @@ input.password-field {
   width: 16em;
   margin-bottom: 0.4em;
 }
-div.password-confirm {
+div.password-confirm-title {
   float: right;  /* LTR */
   margin-top: 1.5em;
   visibility: hidden;
diff --git a/modules/user/user.js b/modules/user/user.js
index 4cf9816..5ec5e35 100644
--- a/modules/user/user.js
+++ b/modules/user/user.js
@@ -16,9 +16,9 @@ Drupal.behaviors.password = {
       innerWrapper.addClass('password-parent');
 
       // Add the password confirmation layer.
-      $('input.password-confirm', outerWrapper).parent().prepend('<div class="password-confirm">' + translate['confirmTitle'] + ' <span></span></div>').addClass('confirm-parent');
+      $('input.password-confirm', outerWrapper).parent().prepend('<div class="password-confirm-title">' + translate['confirmTitle'] + ' <span></span></div>').addClass('confirm-parent');
       var confirmInput = $('input.password-confirm', outerWrapper);
-      var confirmResult = $('div.password-confirm', outerWrapper);
+      var confirmResult = $('div.password-confirm-title', outerWrapper);
       var confirmChild = $('span', confirmResult);
 
       // Add the description box.
