diff --git a/config/example-extras.cfg b/config/example-extras.cfg
index 97183b7cd..67b725b46 100644
--- a/config/example-extras.cfg
+++ b/config/example-extras.cfg
@@ -27,6 +27,24 @@
 #   activation.
 
 
+# Multi-stepper axes. On a cartesian style printer, the stepper
+# controlling a given axis may have additional config blocks defining
+# steppers that should be stepped in concert with the primary
+# stepper. One may define any number of sections with a numeric suffix
+# starting at 1 (for example, "stepper_z1", "stepper_z2", etc.).
+#[stepper_z1]
+#step_pin: ar36
+#dir_pin: ar34
+#enable_pin: !ar30
+#step_distance: .005
+#   See the example.cfg for the definition of the above parameters.
+#endstop_pin: ^ar19
+#   If an endstop_pin is defined for the additional stepper then the
+#   stepper will home until the endstop is triggered. Otherwise, the
+#   endstop will home until the endstop on the primary stepper for the
+#   axis is triggered.
+
+
 # Heater cooling fans (one may define any number of sections with a
 # "heater_fan" prefix). A "heater fan" is a fan that will be enabled
 # whenever its associated heater is active. In the event of an MCU
diff --git a/klippy/cartesian.py b/klippy/cartesian.py
index 4907b6d17..2f4651ad1 100644
--- a/klippy/cartesian.py
+++ b/klippy/cartesian.py
@@ -10,7 +10,7 @@ StepList = (0, 1, 2)
 
 class CartKinematics:
     def __init__(self, toolhead, printer, config):
-        self.steppers = [stepper.PrinterHomingStepper(
+        self.steppers = [stepper.LookupMultiHomingStepper(
             printer, config.getsection('stepper_' + n))
                          for n in ['x', 'y', 'z']]
         max_velocity, max_accel = toolhead.get_max_velocity()
diff --git a/klippy/corexy.py b/klippy/corexy.py
index 8b92d118a..dd62cf1c4 100644
--- a/klippy/corexy.py
+++ b/klippy/corexy.py
@@ -10,9 +10,13 @@ StepList = (0, 1, 2)
 
 class CoreXYKinematics:
     def __init__(self, toolhead, printer, config):
-        self.steppers = [stepper.PrinterHomingStepper(
-            printer, config.getsection('stepper_' + n))
-                         for n in ['x', 'y', 'z']]
+        self.steppers = [
+            stepper.PrinterHomingStepper(
+                printer, config.getsection('stepper_x')),
+            stepper.PrinterHomingStepper(
+                printer, config.getsection('stepper_y')),
+            stepper.LookupMultiHomingStepper(
+                printer, config.getsection('stepper_z'))]
         self.steppers[0].mcu_endstop.add_stepper(self.steppers[1].mcu_stepper)
         self.steppers[1].mcu_endstop.add_stepper(self.steppers[0].mcu_stepper)
         max_velocity, max_accel = toolhead.get_max_velocity()
diff --git a/klippy/stepper.py b/klippy/stepper.py
index 692273c06..0574c4bf9 100644
--- a/klippy/stepper.py
+++ b/klippy/stepper.py
@@ -143,3 +143,49 @@ class PrinterHomingStepper(PrinterStepper):
                 "Endstop %s incorrect phase (got %d vs %d)" % (
                     self.name, pos, self.homing_endstop_phase))
         return delta * self.step_dist
+
+# Wrapper for dual stepper motor support
+class PrinterMultiStepper(PrinterHomingStepper):
+    def __init__(self, printer, config):
+        PrinterHomingStepper.__init__(self, printer, config)
+        self.endstops = PrinterHomingStepper.get_endstops(self)
+        self.extras = []
+        self.all_step_const = [self.step_const]
+        for i in range(1, 99):
+            if not config.has_section(config.section + str(i)):
+                break
+            extraconfig = config.getsection(config.section + str(i))
+            extra = PrinterStepper(printer, extraconfig)
+            self.extras.append(extra)
+            self.all_step_const.append(extra.step_const)
+            extraendstop = extraconfig.get('endstop_pin', None)
+            if extraendstop is not None:
+                mcu_endstop = pins.setup_pin(printer, 'endstop', extraendstop)
+                mcu_endstop.add_stepper(extra.mcu_stepper)
+                self.endstops.append(
+                    (mcu_endstop, extra.mcu_stepper, extra.name))
+            else:
+                self.mcu_endstop.add_stepper(extra.mcu_stepper)
+        self.step_const = self.step_multi_const
+    def step_multi_const(self, print_time, start_pos, dist, start_v, accel):
+        for step_const in self.all_step_const:
+            step_const(print_time, start_pos, dist, start_v, accel)
+    def set_max_jerk(self, max_halt_velocity, max_accel):
+        PrinterHomingStepper.set_max_jerk(self, max_halt_velocity, max_accel)
+        for extra in self.extras:
+            extra.set_max_jerk(max_halt_velocity, max_accel)
+    def set_position(self, pos):
+        PrinterHomingStepper.set_position(self, pos)
+        for extra in self.extras:
+            extra.set_position(pos)
+    def motor_enable(self, print_time, enable=0):
+        PrinterHomingStepper.motor_enable(self, print_time, enable)
+        for extra in self.extras:
+            extra.motor_enable(print_time, enable)
+    def get_endstops(self):
+        return self.endstops
+
+def LookupMultiHomingStepper(printer, config):
+    if not config.has_section(config.section + '1'):
+        return PrinterHomingStepper(printer, config)
+    return PrinterMultiStepper(printer, config)