diff --git a/common/src/com/android/inputmethod/latin/common/Constants.java b/common/src/com/android/inputmethod/latin/common/Constants.java
index 03abb0fddbc2f0d5a0f7ddc0dc453c602af338fe..b491c8cfd7f8dd9f81d7c86aa4f667df4312d8e0 100644
--- a/common/src/com/android/inputmethod/latin/common/Constants.java
+++ b/common/src/com/android/inputmethod/latin/common/Constants.java
@@ -325,6 +325,10 @@ public final class Constants {
     public static final int DECODER_SCORE_SCALAR = 1000000;
     public static final int DECODER_MAX_SCORE = 1000000000;
 
+    public static final int EVENT_BACKSPACE = 1;
+    public static final int EVENT_REJECTION = 2;
+    public static final int EVENT_REVERT = 3;
+
     private Constants() {
         // This utility class is not publicly instantiable.
     }
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
index c22dc287c9802a4f0d4d891e273c72b903abb5b1..9f48501d601839d2e9dcc57d480d331d5ba2ebaa 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
@@ -150,7 +150,9 @@ public interface DictionaryFacilitator {
             @Nonnull final NgramContext ngramContext, final int timeStampInSeconds,
             final boolean blockPotentiallyOffensive);
 
-    void removeWordFromPersonalizedDicts(final String word);
+    void unlearnFromUserHistory(final String word,
+            @Nonnull final NgramContext ngramContext, final int timeStampInSeconds,
+            final int eventType);
 
     // TODO: Revise the way to fusion suggestion results.
     SuggestionResults getSuggestionResults(final WordComposer composer,
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java
index 3d76751ce881d10e1fc4d24f968483c387d62b6d..ba70114e77e645aab288f4ba7359e94b9da9eeab 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java
@@ -654,8 +654,14 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
         }
     }
 
-    public void removeWordFromPersonalizedDicts(final String word) {
-        removeWord(Dictionary.TYPE_USER_HISTORY, word);
+    @Override
+    public void unlearnFromUserHistory(final String word,
+            @Nonnull final NgramContext ngramContext, final int timeStampInSeconds,
+            final int eventType) {
+        // TODO: Decide whether or not to remove the word on EVENT_BACKSPACE.
+        if (eventType != Constants.EVENT_BACKSPACE) {
+            removeWord(Dictionary.TYPE_USER_HISTORY, word);
+        }
     }
 
     // TODO: Revise the way to fusion suggestion results.
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index 9154cc35a9a67ea24d90de6b6c32652304a1097c..56be23f5be6b8139c343cfd08fc2c07ddaee2b5f 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -1007,7 +1007,8 @@ public final class InputLogic {
                 mWordComposer.reset();
                 mWordComposer.setRejectedBatchModeSuggestion(rejectedSuggestion);
                 if (!TextUtils.isEmpty(rejectedSuggestion)) {
-                    mDictionaryFacilitator.removeWordFromPersonalizedDicts(rejectedSuggestion);
+                    unlearnWord(rejectedSuggestion, inputTransaction.mSettingsValues,
+                            Constants.EVENT_REJECTION);
                 }
                 StatsUtils.onBackspaceWordDelete(rejectedSuggestion.length());
             } else {
@@ -1060,6 +1061,8 @@ public final class InputLogic {
                 }
             }
 
+            boolean hasUnlearnedWordBeingDeleted = false;
+
             // No cancelling of commit/double space/swap: we have a regular backspace.
             // We should backspace one char and restart suggestion if at the end of a word.
             if (mConnection.hasSelection()) {
@@ -1090,6 +1093,11 @@ public final class InputLogic {
                     sendDownUpKeyEvent(KeyEvent.KEYCODE_DEL);
                     int totalDeletedLength = 1;
                     if (mDeleteCount > Constants.DELETE_ACCELERATE_AT) {
+                        // If this is an accelerated (i.e., double) deletion, then we need to
+                        // consider unlearning here too because we may have just entered the
+                        // previous word, and the next deletion will currupt it.
+                        hasUnlearnedWordBeingDeleted |= unlearnWordBeingDeleted(
+                                inputTransaction.mSettingsValues, currentKeyboardScriptId);
                         sendDownUpKeyEvent(KeyEvent.KEYCODE_DEL);
                         totalDeletedLength++;
                     }
@@ -1112,6 +1120,11 @@ public final class InputLogic {
                     mConnection.deleteSurroundingText(lengthToDelete, 0);
                     int totalDeletedLength = lengthToDelete;
                     if (mDeleteCount > Constants.DELETE_ACCELERATE_AT) {
+                        // If this is an accelerated (i.e., double) deletion, then we need to
+                        // consider unlearning here too because we may have just entered the
+                        // previous word, and the next deletion will currupt it.
+                        hasUnlearnedWordBeingDeleted |= unlearnWordBeingDeleted(
+                                inputTransaction.mSettingsValues, currentKeyboardScriptId);
                         final int codePointBeforeCursorToDeleteAgain =
                                 mConnection.getCodePointBeforeCursor();
                         if (codePointBeforeCursorToDeleteAgain != Constants.NOT_A_CODE) {
@@ -1124,6 +1137,11 @@ public final class InputLogic {
                     StatsUtils.onBackspacePressed(totalDeletedLength);
                 }
             }
+            if (!hasUnlearnedWordBeingDeleted) {
+                // Consider unlearning the word being deleted (if we have not done so already).
+                unlearnWordBeingDeleted(
+                        inputTransaction.mSettingsValues, currentKeyboardScriptId);
+            }
             if (inputTransaction.mSettingsValues.isSuggestionsEnabledPerUserSettings()
                     && inputTransaction.mSettingsValues.mSpacingAndPunctuations
                             .mCurrentLanguageHasSpaces
@@ -1135,6 +1153,38 @@ public final class InputLogic {
         }
     }
 
+    boolean unlearnWordBeingDeleted(
+            final SettingsValues settingsValues,final int currentKeyboardScriptId) {
+        // If we just started backspacing to delete a previous word (but have not
+        // entered the composing state yet), unlearn the word.
+        // TODO: Consider tracking whether or not this word was typed by the user.
+        if (!mConnection.hasSelection()
+                && settingsValues.isSuggestionsEnabledPerUserSettings()
+                && settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces
+                && !mConnection.isCursorFollowedByWordCharacter(
+                        settingsValues.mSpacingAndPunctuations)) {
+            final TextRange range = mConnection.getWordRangeAtCursor(
+                    settingsValues.mSpacingAndPunctuations,
+                    currentKeyboardScriptId);
+            final String wordBeingDeleted = range.mWord.toString();
+            if (!wordBeingDeleted.isEmpty()) {
+                unlearnWord(wordBeingDeleted, settingsValues,
+                        Constants.EVENT_BACKSPACE);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    void unlearnWord(final String word, final SettingsValues settingsValues, final int eventType) {
+        final NgramContext ngramContext = mConnection.getNgramContextFromNthPreviousWord(
+            settingsValues.mSpacingAndPunctuations, 2);
+        final int timeStampInSeconds = (int)TimeUnit.MILLISECONDS.toSeconds(
+            System.currentTimeMillis());
+        mDictionaryFacilitator.unlearnFromUserHistory(
+            word, ngramContext, timeStampInSeconds, eventType);
+    }
+
     /**
      * Handle a press on the language switch key (the "globe key")
      */
@@ -1546,7 +1596,8 @@ public final class InputLogic {
         }
         mConnection.deleteSurroundingText(deleteLength, 0);
         if (!TextUtils.isEmpty(committedWord)) {
-            mDictionaryFacilitator.removeWordFromPersonalizedDicts(committedWordString);
+            unlearnWord(committedWordString, inputTransaction.mSettingsValues,
+                    Constants.EVENT_REVERT);
         }
         final String stringToCommit = originallyTypedWord +
                 (usePhantomSpace ? "" : separatorString);