diff --git includes/ajax.inc includes/ajax.inc
index f77bd90..a9085c3 100644
--- includes/ajax.inc
+++ includes/ajax.inc
@@ -199,6 +199,11 @@ function ajax_get_form() {
  * Menu callback for AJAX callbacks through the #ajax['callback'] Form API property.
  */
 function ajax_form_callback() {
+  // Find the triggering element, which was set up for us on the client side.
+  $triggering_element_path = !empty($_POST['ajax_triggering_element']) ? $_POST['ajax_triggering_element'] : NULL;
+  // Destroy field so it can't conflict in validation.
+  unset($_POST['ajax_triggering_element']);
+
   list($form, $form_state, $form_id, $form_build_id) = ajax_get_form();
 
   // Build, validate and if possible, submit the form.
@@ -208,9 +213,31 @@ function ajax_form_callback() {
   // drupal_process_form() set up.
   $form = drupal_rebuild_form($form_id, $form_state, $form_build_id);
 
-  // Get the callback function from the clicked button.
-  $ajax = $form_state['clicked_button']['#ajax'];
-  $callback = $ajax['callback'];
+  /**
+   * $triggering_element_path in a simple form might just be 'myselect', which
+   * would mean we should use the element $form['myselect']. However, if fieldsets
+   * are in use, it might be fieldset1[fieldset2][myselect] in the case of a double-
+   * nested fieldset, so we would have to find our way to $form['fieldset1']['fieldset2']['myselect'].
+   * Here we break up the formpath and use it to traverse the form
+   * to find the element.
+   */
+  if (!empty($triggering_element_path)) {
+    $triggering_element = $form;
+    foreach (explode('/', $triggering_element_path) as $key) {
+      if (!empty($triggering_element[$key])) {
+        $triggering_element = $triggering_element[$key];
+      }
+      else {
+        $triggering_element = NULL;
+        break;
+      }
+    }
+  }
+
+  // Now that we have the element, get a callback if there is one.
+  if (!empty($triggering_element['#ajax']['callback'])) {
+    $callback = $triggering_element['#ajax']['callback'];
+  }
   if (function_exists($callback)) {
     $html = $callback($form, $form_state);
 
@@ -305,6 +332,7 @@ function ajax_process_form($element) {
       'method'   => empty($element['#ajax']['method']) ? 'replace' : $element['#ajax']['method'],
       'progress' => empty($element['#ajax']['progress']) ? array('type' => 'throbber') : $element['#ajax']['progress'],
       'button'   => isset($element['#executes_submit_callback']) ? array($element['#name'] => $element['#value']) : FALSE,
+      'formPath' => implode('/', $element['#array_parents']),
     );
 
     // Convert a simple #ajax['progress'] type string into an array.
diff --git misc/ajax.js misc/ajax.js
index 0804992..4a8f7a0 100644
--- misc/ajax.js
+++ misc/ajax.js
@@ -96,7 +96,7 @@ Drupal.ajax = function (base, element, element_settings) {
       type: 'bar',
       message: 'Please wait...'
     },
-    button: {},
+    button: {}
   };
 
   $.extend(this, defaults, element_settings);
@@ -183,6 +183,10 @@ Drupal.ajax.prototype.beforeSubmit = function (form_values, element, options) {
   // Disable the element that received the change.
   $(this.element).addClass('progress-disabled').attr('disabled', true);
 
+  // Server-side code needs to know what element triggered the call, so it can
+  // find the #ajax binding.
+  form_values.push({name: 'ajax_triggering_element', value: this.formPath});
+
   // Insert progressbar or throbber.
   if (this.progress.type == 'bar') {
     var progressBar = new Drupal.progressBar('ajax-progress-' + this.element.id, eval(this.progress.update_callback), this.progress.method, eval(this.progress.error_callback));
