diff --git a/src/applications/calendar/application/PhabricatorCalendarApplication.php b/src/applications/calendar/application/PhabricatorCalendarApplication.php
--- a/src/applications/calendar/application/PhabricatorCalendarApplication.php
+++ b/src/applications/calendar/application/PhabricatorCalendarApplication.php
@@ -57,7 +57,7 @@
             => 'PhabricatorCalendarEventEditController',
           'drag/(?P<id>[1-9]\d*)/'
             => 'PhabricatorCalendarEventDragController',
-          'cancel/(?P<id>[1-9]\d*)/'
+          'cancel/(?P<id>[1-9]\d*)/(?:(?P<sequence>\d+)/)?'
             => 'PhabricatorCalendarEventCancelController',
           '(?P<action>join|decline|accept)/(?P<id>[1-9]\d*)/'
             => 'PhabricatorCalendarEventJoinController',
diff --git a/src/applications/calendar/controller/PhabricatorCalendarController.php b/src/applications/calendar/controller/PhabricatorCalendarController.php
--- a/src/applications/calendar/controller/PhabricatorCalendarController.php
+++ b/src/applications/calendar/controller/PhabricatorCalendarController.php
@@ -26,4 +26,47 @@
     return $crumbs;
   }
 
+  protected function getEventAtIndexForGhostPHID($viewer, $phid, $index) {
+    $result = id(new PhabricatorCalendarEventQuery())
+      ->setViewer($viewer)
+      ->withInstanceSequencePairs(
+        array(
+          array(
+            $phid,
+            $index,
+          ),
+        ))
+      ->requireCapabilities(
+        array(
+          PhabricatorPolicyCapability::CAN_VIEW,
+          PhabricatorPolicyCapability::CAN_EDIT,
+        ))
+      ->executeOne();
+
+    return $result;
+  }
+
+  protected function createEventFromGhost($viewer, $event, $index) {
+    $invitees = $event->getInvitees();
+
+    $new_ghost = $event->generateNthGhost($index, $viewer);
+    $new_ghost->attachParentEvent($event);
+
+    $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
+    $new_ghost
+      ->setID(null)
+      ->setPHID(null)
+      ->removeViewerTimezone($viewer)
+      ->save();
+    $ghost_invitees = array();
+    foreach ($invitees as $invitee) {
+      $ghost_invitee = clone $invitee;
+      $ghost_invitee
+        ->setID(null)
+        ->setEventPHID($new_ghost->getPHID())
+        ->save();
+    }
+    unset($unguarded);
+    return $new_ghost;
+  }
 }
diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventCancelController.php b/src/applications/calendar/controller/PhabricatorCalendarEventCancelController.php
--- a/src/applications/calendar/controller/PhabricatorCalendarEventCancelController.php
+++ b/src/applications/calendar/controller/PhabricatorCalendarEventCancelController.php
@@ -12,8 +12,9 @@
   public function processRequest() {
     $request  = $this->getRequest();
     $user     = $request->getUser();
+    $sequence = $request->getURIData('sequence');
 
-    $status = id(new PhabricatorCalendarEventQuery())
+    $event = id(new PhabricatorCalendarEventQuery())
       ->setViewer($user)
       ->withIDs(array($this->id))
       ->requireCapabilities(
@@ -23,15 +24,40 @@
         ))
       ->executeOne();
 
-    if (!$status) {
+    if ($sequence) {
+      $parent_event = $event;
+      $event = $parent_event->generateNthGhost($sequence, $user);
+      $event->attachParentEvent($parent_event);
+    }
+
+    if (!$event) {
       return new Aphront404Response();
     }
 
-    $cancel_uri = '/E'.$status->getID();
+    if (!$sequence) {
+      $cancel_uri = '/E'.$event->getID();
+    } else {
+      $cancel_uri = '/E'.$event->getID().'/'.$sequence;
+    }
+
+    $is_cancelled = $event->getIsCancelled();
+    $is_parent_cancelled = $event->getIsParentCancelled();
+    $is_recurring = $event->getIsRecurring();
+    $instance_of = $event->getInstanceOfEventPHID();
+
     $validation_exception = null;
-    $is_cancelled = $status->getIsCancelled();
 
     if ($request->isFormPost()) {
+      if ($is_cancelled && $sequence) {
+        return id(new AphrontRedirectResponse())->setURI($cancel_uri);
+      } else if ($sequence) {
+        $event = $this->createEventFromGhost(
+          $user,
+          $event,
+          $sequence);
+        $event->applyViewerTimezone($user);
+      }
+
       $xactions = array();
 
       $xaction = id(new PhabricatorCalendarEventTransaction())
@@ -46,7 +72,7 @@
         ->setContinueOnMissingFields(true);
 
       try {
-        $editor->applyTransactions($status, array($xaction));
+        $editor->applyTransactions($event, array($xaction));
         return id(new AphrontRedirectResponse())->setURI($cancel_uri);
       } catch (PhabricatorApplicationTransactionValidationException $ex) {
         $validation_exception = $ex;
@@ -54,15 +80,44 @@
     }
 
     if ($is_cancelled) {
-      $title = pht('Reinstate Event');
-      $paragraph = pht('Reinstate this event?');
-      $cancel = pht('Don\'t Reinstate Event');
-      $submit = pht('Reinstate Event');
+      if ($sequence || $is_parent_cancelled) {
+        $title = pht('Cannot Reinstate Instance');
+        $paragraph = pht('Cannot reinstate an instance of a
+          cancelled recurring event.');
+        $cancel = pht('Cancel');
+        $submit = null;
+      } else if ($is_recurring && !$instance_of) {
+        $title = pht('Reinstate Recurrence');
+        $paragraph = pht('Reinstate the entire series
+          of recurring events?');
+        $cancel = pht('Don\'t Reinstate Recurrence');
+        $submit = pht('Reinstate Recurrence');
+      } else {
+        $title = pht('Reinstate Event');
+        $paragraph = pht('Reinstate this event?');
+        $cancel = pht('Don\'t Reinstate Event');
+        $submit = pht('Reinstate Event');
+      }
     } else {
-      $title = pht('Cancel Event');
-      $paragraph = pht('You can always reinstate the event later.');
-      $cancel = pht('Don\'t Cancel Event');
-      $submit = pht('Cancel Event');
+      if ($sequence) {
+        $title = pht('Cancel Instance');
+        $paragraph = pht('Cancel just this instance
+          of a recurring event.');
+        $cancel = pht('Don\'t Cancel Instance');
+        $submit = pht('Cancel Instance');
+      } else if ($is_recurring && !$instance_of) {
+        $title = pht('Cancel Recurrence');
+        $paragraph = pht('Cancel the entire series
+          of recurring events?');
+        $cancel = pht('Don\'t Cancel Recurrence');
+        $submit = pht('Cancel Recurrence');
+      } else {
+        $title = pht('Cancel Event');
+        $paragraph = pht('You can always reinstate
+          the event later.');
+        $cancel = pht('Don\'t Cancel Event');
+        $submit = pht('Cancel Event');
+      }
     }
 
     return $this->newDialog()
diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php b/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php
--- a/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php
+++ b/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php
@@ -78,14 +78,15 @@
       $cancel_uri = $this->getApplicationURI();
     } else {
       $event = id(new PhabricatorCalendarEventQuery())
-        ->setViewer($viewer)
-        ->withIDs(array($this->id))
-        ->requireCapabilities(
-          array(
-            PhabricatorPolicyCapability::CAN_VIEW,
-            PhabricatorPolicyCapability::CAN_EDIT,
-          ))
-        ->executeOne();
+      ->setViewer($viewer)
+      ->withIDs(array($this->id))
+      ->requireCapabilities(
+        array(
+          PhabricatorPolicyCapability::CAN_VIEW,
+          PhabricatorPolicyCapability::CAN_EDIT,
+        ))
+      ->executeOne();
+
       if (!$event) {
         return new Aphront404Response();
       }
@@ -93,47 +94,23 @@
       if ($request->getURIData('sequence')) {
         $index = $request->getURIData('sequence');
 
-        $result = id(new PhabricatorCalendarEventQuery())
-          ->setViewer($viewer)
-          ->withInstanceSequencePairs(
-            array(
-              array(
-                $event->getPHID(),
-                $index,
-              ),
-            ))
-          ->requireCapabilities(
-            array(
-              PhabricatorPolicyCapability::CAN_VIEW,
-              PhabricatorPolicyCapability::CAN_EDIT,
-            ))
-          ->executeOne();
+        $result = $this->getEventAtIndexForGhostPHID(
+          $viewer,
+          $event->getPHID(),
+          $index);
 
         if ($result) {
           return id(new AphrontRedirectResponse())
             ->setURI('/calendar/event/edit/'.$result->getID().'/');
         }
 
-        $invitees = $event->getInvitees();
-
-        $new_ghost = $event->generateNthGhost($index, $viewer);
-        $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
-        $new_ghost
-          ->setID(null)
-          ->setPHID(null)
-          ->removeViewerTimezone($viewer)
-          ->save();
-        $ghost_invitees = array();
-        foreach ($invitees as $invitee) {
-          $ghost_invitee = clone $invitee;
-          $ghost_invitee
-            ->setID(null)
-            ->setEventPHID($new_ghost->getPHID())
-            ->save();
-        }
-        unset($unguarded);
+        $event = $this->createEventFromGhost(
+          $viewer,
+          $event,
+          $index);
+
         return id(new AphrontRedirectResponse())
-          ->setURI('/calendar/event/edit/'.$new_ghost->getID().'/');
+          ->setURI('/calendar/event/edit/'.$event->getID().'/');
       }
 
       $end_value = AphrontFormDateControlValue::newFromEpoch(
diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php b/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php
--- a/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php
+++ b/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php
@@ -27,12 +27,25 @@
       return new Aphront404Response();
     }
 
-    if ($sequence && $event->getIsRecurring()) {
-      $parent_event = $event;
-      $event = $event->generateNthGhost($sequence, $viewer);
-      $event->attachParentEvent($parent_event);
-    } else if ($sequence) {
-      return new Aphront404Response();
+    if ($sequence) {
+      $result = $this->getEventAtIndexForGhostPHID(
+        $viewer,
+        $event->getPHID(),
+        $sequence);
+
+      if ($result) {
+        $parent_event = $event;
+        $event = $result;
+        $event->attachParentEvent($parent_event);
+        return id(new AphrontRedirectResponse())
+          ->setURI('/E'.$result->getID());
+      } else if ($sequence && $event->getIsRecurring()) {
+        $parent_event = $event;
+        $event = $event->generateNthGhost($sequence, $viewer);
+        $event->attachParentEvent($parent_event);
+      } else if ($sequence) {
+        return new Aphront404Response();
+      }
     }
 
     $title = 'E'.$event->getID();
@@ -178,21 +191,46 @@
           ->setWorkflow(true));
     }
 
+    $cancel_uri = $this->getApplicationURI("event/cancel/{$id}/");
+
+    if ($event->getIsGhostEvent()) {
+      $index = $event->getSequenceIndex();
+      $can_reinstate = $event->getIsParentCancelled();
+
+      $cancel_label = pht('Cancel This Instance');
+      $reinstate_label = pht('Reinstate This Instance');
+      $cancel_disabled = (!$can_edit || $can_reinstate);
+      $cancel_uri = $this->getApplicationURI("event/cancel/{$id}/{$index}/");
+    } else if ($event->getInstanceOfEventPHID()) {
+      $can_reinstate = $event->getIsParentCancelled();
+      $cancel_label = pht('Cancel This Instance');
+      $reinstate_label = pht('Reinstate This Instance');
+      $cancel_disabled = (!$can_edit || $can_reinstate);
+    } else if ($event->getIsRecurring()) {
+      $cancel_label = pht('Cancel Recurrence');
+      $reinstate_label = pht('Reinstate Recurrence');
+      $cancel_disabled = !$can_edit;
+    } else {
+      $cancel_label = pht('Cancel Event');
+      $reinstate_label = pht('Reinstate Event');
+      $cancel_disabled = !$can_edit;
+    }
+
     if ($is_cancelled) {
       $actions->addAction(
         id(new PhabricatorActionView())
-          ->setName(pht('Reinstate Event'))
+          ->setName($reinstate_label)
           ->setIcon('fa-plus')
-          ->setHref($this->getApplicationURI("event/cancel/{$id}/"))
-          ->setDisabled(!$can_edit)
+          ->setHref($cancel_uri)
+          ->setDisabled($cancel_disabled)
           ->setWorkflow(true));
     } else {
       $actions->addAction(
         id(new PhabricatorActionView())
-          ->setName(pht('Cancel Event'))
+          ->setName($cancel_label)
           ->setIcon('fa-times')
-          ->setHref($this->getApplicationURI("event/cancel/{$id}/"))
-          ->setDisabled(!$can_edit)
+          ->setHref($cancel_uri)
+          ->setDisabled($cancel_disabled)
           ->setWorkflow(true));
     }
 
diff --git a/src/applications/calendar/storage/PhabricatorCalendarEvent.php b/src/applications/calendar/storage/PhabricatorCalendarEvent.php
--- a/src/applications/calendar/storage/PhabricatorCalendarEvent.php
+++ b/src/applications/calendar/storage/PhabricatorCalendarEvent.php
@@ -348,6 +348,10 @@
   }
 
   public function getIsParentCancelled() {
+    if ($this->instanceOfEventPHID == null) {
+      return false;
+    }
+
     $recurring_event = $this->getParentEvent();
     if ($recurring_event->getIsCancelled()) {
       return true;