diff --git a/src/org/openstreetmap/josm/command/Command.java b/src/org/openstreetmap/josm/command/Command.java
index 945967a..e6e3bfc 100644
--- a/src/org/openstreetmap/josm/command/Command.java
+++ b/src/org/openstreetmap/josm/command/Command.java
@@ -147,7 +147,10 @@ public abstract class Command extends PseudoCommand {
     /**
      * Executes the command on the dataset. This implementation will remember all
      * primitives returned by fillModifiedData for restoring them on undo.
+     * <p>
+     * The layer should be invalidated after execution so that it can be re-painted.
      * @return true
+     * @see #invalidateAffectedLayers()
      */
     public boolean executeCommand() {
         CloneVisitor visitor = new CloneVisitor();
@@ -299,4 +302,15 @@ public abstract class Command extends PseudoCommand {
         return Objects.equals(cloneMap, command.cloneMap) &&
                 Objects.equals(layer, command.layer);
     }
+
+    /**
+     * Invalidate all layers that were affected by this command.
+     * @see Layer#invalidate()
+     */
+    public void invalidateAffectedLayers() {
+        OsmDataLayer layer = getLayer();
+        if (layer != null) {
+            layer.invalidate();
+        }
+    }
 }
diff --git a/src/org/openstreetmap/josm/command/SequenceCommand.java b/src/org/openstreetmap/josm/command/SequenceCommand.java
index 22428c8..eb74259 100644
--- a/src/org/openstreetmap/josm/command/SequenceCommand.java
+++ b/src/org/openstreetmap/josm/command/SequenceCommand.java
@@ -125,6 +125,14 @@ public class SequenceCommand extends Command {
     }
 
     @Override
+    public void invalidateAffectedLayers() {
+        super.invalidateAffectedLayers();
+        for (Command c : sequence) {
+            c.invalidateAffectedLayers();
+        }
+    }
+
+    @Override
     public int hashCode() {
         return Objects.hash(super.hashCode(), Arrays.hashCode(sequence), sequenceComplete, name, continueOnError);
     }
diff --git a/src/org/openstreetmap/josm/data/UndoRedoHandler.java b/src/org/openstreetmap/josm/data/UndoRedoHandler.java
index 7118052..bb39aae 100644
--- a/src/org/openstreetmap/josm/data/UndoRedoHandler.java
+++ b/src/org/openstreetmap/josm/data/UndoRedoHandler.java
@@ -14,9 +14,15 @@ import org.openstreetmap.josm.gui.layer.LayerManager.LayerAddEvent;
 import org.openstreetmap.josm.gui.layer.LayerManager.LayerChangeListener;
 import org.openstreetmap.josm.gui.layer.LayerManager.LayerOrderChangeEvent;
 import org.openstreetmap.josm.gui.layer.LayerManager.LayerRemoveEvent;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer.CommandQueueListener;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
 
+/**
+ * This is the global undo/redo handler for all {@link OsmDataLayer}s.
+ * <p>
+ * If you want to change a data layer, you can use {@link #add(Command)} to execute a command on it and make that command undoable.
+ */
 public class UndoRedoHandler implements LayerChangeListener {
 
     /**
@@ -44,6 +50,7 @@ public class UndoRedoHandler implements LayerChangeListener {
     public void addNoRedraw(final Command c) {
         CheckParameterUtil.ensureParameterNotNull(c, "c");
         c.executeCommand();
+        c.invalidateAffectedLayers();
         commands.add(c);
         // Limit the number of commands in the undo list.
         // Currently you have to undo the commands one by one. If
@@ -54,14 +61,11 @@ public class UndoRedoHandler implements LayerChangeListener {
         redoCommands.clear();
     }
 
+    /**
+     * Fires a commands change event after adding a command.
+     */
     public void afterAdd() {
         fireCommandsChanged();
-
-        // the command may have changed the selection so tell the listeners about the current situation
-        DataSet ds = Main.getLayerManager().getEditDataSet();
-        if (ds != null) {
-            ds.fireSelectionChanged();
-        }
     }
 
     /**
@@ -69,8 +73,13 @@ public class UndoRedoHandler implements LayerChangeListener {
      * @param c The command to execute. Must not be {@code null}.
      */
     public synchronized void add(final Command c) {
+        DataSet ds = Main.getLayerManager().getEditDataSet();
+        Collection<? extends OsmPrimitive> oldSelection = ds.getSelected();
         addNoRedraw(c);
         afterAdd();
+
+        // the command may have changed the selection so tell the listeners about the current situation
+        fireIfSelectionChanged(ds, oldSelection);
     }
 
     /**
@@ -87,25 +96,24 @@ public class UndoRedoHandler implements LayerChangeListener {
     public synchronized void undo(int num) {
         if (commands.isEmpty())
             return;
-        Collection<? extends OsmPrimitive> oldSelection = Main.getLayerManager().getEditDataSet().getSelected();
-        Main.getLayerManager().getEditDataSet().beginUpdate();
+        DataSet ds = Main.getLayerManager().getEditDataSet();
+        Collection<? extends OsmPrimitive> oldSelection = ds.getSelected();
+        ds.beginUpdate();
         try {
             for (int i = 1; i <= num; ++i) {
                 final Command c = commands.removeLast();
                 c.undoCommand();
+                c.invalidateAffectedLayers();
                 redoCommands.addFirst(c);
                 if (commands.isEmpty()) {
                     break;
                 }
             }
         } finally {
-            Main.getLayerManager().getEditDataSet().endUpdate();
+            ds.endUpdate();
         }
         fireCommandsChanged();
-        Collection<? extends OsmPrimitive> newSelection = Main.getLayerManager().getEditDataSet().getSelected();
-        if (!oldSelection.equals(newSelection)) {
-            Main.getLayerManager().getEditDataSet().fireSelectionChanged();
-        }
+        fireIfSelectionChanged(ds, oldSelection);
     }
 
     /**
@@ -122,34 +130,50 @@ public class UndoRedoHandler implements LayerChangeListener {
     public void redo(int num) {
         if (redoCommands.isEmpty())
             return;
-        Collection<? extends OsmPrimitive> oldSelection = Main.getLayerManager().getEditDataSet().getSelected();
+        DataSet ds = Main.getLayerManager().getEditDataSet();
+        Collection<? extends OsmPrimitive> oldSelection = ds.getSelected();
         for (int i = 0; i < num; ++i) {
             final Command c = redoCommands.removeFirst();
             c.executeCommand();
+            c.invalidateAffectedLayers();
             commands.add(c);
             if (redoCommands.isEmpty()) {
                 break;
             }
         }
         fireCommandsChanged();
-        Collection<? extends OsmPrimitive> newSelection = Main.getLayerManager().getEditDataSet().getSelected();
+        fireIfSelectionChanged(ds, oldSelection);
+    }
+
+    private static void fireIfSelectionChanged(DataSet ds, Collection<? extends OsmPrimitive> oldSelection) {
+        Collection<? extends OsmPrimitive> newSelection = ds.getSelected();
         if (!oldSelection.equals(newSelection)) {
-            Main.getLayerManager().getEditDataSet().fireSelectionChanged();
+            ds.fireSelectionChanged();
         }
     }
 
-    public void fireCommandsChanged() {
+    /**
+     * Fires a command change to all listeners.
+     */
+    private void fireCommandsChanged() {
         for (final CommandQueueListener l : listenerCommands) {
             l.commandChanged(commands.size(), redoCommands.size());
         }
     }
 
+    /**
+     * Resets the undo/redo list.
+     */
     public void clean() {
         redoCommands.clear();
         commands.clear();
         fireCommandsChanged();
     }
 
+    /**
+     * Resets all commands that affect the given layer.
+     * @param layer The layer that was affected.
+     */
     public void clean(Layer layer) {
         if (layer == null)
             return;
diff --git a/src/org/openstreetmap/josm/gui/dialogs/ValidatorDialog.java b/src/org/openstreetmap/josm/gui/dialogs/ValidatorDialog.java
index 1b37a88..28febcc 100644
--- a/src/org/openstreetmap/josm/gui/dialogs/ValidatorDialog.java
+++ b/src/org/openstreetmap/josm/gui/dialogs/ValidatorDialog.java
@@ -607,16 +607,16 @@ public class ValidatorDialog extends ToggleDialog implements SelectionChangedLis
         }
 
         @Override
-        protected void realRun() throws SAXException, IOException,
-        OsmTransferException {
+        protected void realRun() throws SAXException, IOException, OsmTransferException {
             ProgressMonitor monitor = getProgressMonitor();
             try {
                 monitor.setTicksCount(testErrors.size());
+                final DataSet ds = Main.getLayerManager().getEditDataSet();
                 int i = 0;
                 SwingUtilities.invokeAndWait(new Runnable() {
                     @Override
                     public void run() {
-                        Main.getLayerManager().getEditDataSet().beginUpdate();
+                        ds.beginUpdate();
                     }
                 });
                 try {
@@ -632,7 +632,7 @@ public class ValidatorDialog extends ToggleDialog implements SelectionChangedLis
                     SwingUtilities.invokeAndWait(new Runnable() {
                         @Override
                         public void run() {
-                            Main.getLayerManager().getEditDataSet().endUpdate();
+                            ds.endUpdate();
                         }
                     });
                 }
@@ -643,7 +643,7 @@ public class ValidatorDialog extends ToggleDialog implements SelectionChangedLis
                         Main.main.undoRedo.afterAdd();
                         Main.map.repaint();
                         tree.resetErrors();
-                        Main.getLayerManager().getEditDataSet().fireSelectionChanged();
+                        ds.fireSelectionChanged();
                     }
                 });
             } catch (InterruptedException | InvocationTargetException e) {
diff --git a/test/unit/org/openstreetmap/josm/actions/mapmode/DrawActionTest.java b/test/unit/org/openstreetmap/josm/actions/mapmode/DrawActionTest.java
index e7ac1b4..1bd00dc 100644
--- a/test/unit/org/openstreetmap/josm/actions/mapmode/DrawActionTest.java
+++ b/test/unit/org/openstreetmap/josm/actions/mapmode/DrawActionTest.java
@@ -52,6 +52,7 @@ public class DrawActionTest {
     public void testTicket12011() throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
         DataSet dataSet = new DataSet();
         OsmDataLayer layer = new OsmDataLayer(dataSet, OsmDataLayer.createNewName(), null);
+        Main.getLayerManager().addLayer(layer);
 
         Field mapView = MapFrame.class.getDeclaredField("mapView");
         Utils.setObjectsAccessible(mapView);
@@ -67,7 +68,6 @@ public class DrawActionTest {
         w.setNodes(Arrays.asList(new Node[] {n1, n2}));
         dataSet.addPrimitive(w);
 
-        Main.getLayerManager().addLayer(layer);
         try {
             assertTrue(Main.map.selectDrawTool(false));
 
