diff --git a/src/org/openstreetmap/josm/actions/ImageryAdjustAction.java b/src/org/openstreetmap/josm/actions/ImageryAdjustAction.java
index a35cac3..09a6e35 100644
--- a/src/org/openstreetmap/josm/actions/ImageryAdjustAction.java
+++ b/src/org/openstreetmap/josm/actions/ImageryAdjustAction.java
@@ -27,7 +27,8 @@ import org.openstreetmap.josm.actions.mapmode.MapMode;
 import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.imagery.OffsetBookmark;
 import org.openstreetmap.josm.gui.ExtendedDialog;
-import org.openstreetmap.josm.gui.layer.ImageryLayer;
+import org.openstreetmap.josm.gui.layer.AbstractTileSourceLayer;
+import org.openstreetmap.josm.gui.layer.imagery.TileSourceDisplaySettings;
 import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
 import org.openstreetmap.josm.gui.widgets.JosmTextField;
 import org.openstreetmap.josm.tools.GBC;
@@ -41,16 +42,16 @@ public class ImageryAdjustAction extends MapMode implements AWTEventListener {
     private static volatile ImageryOffsetDialog offsetDialog;
     private static Cursor cursor = ImageProvider.getCursor("normal", "move");
 
-    private double oldDx, oldDy;
+    private EastNorth old;
     private EastNorth prevEastNorth;
-    private transient ImageryLayer layer;
+    private transient AbstractTileSourceLayer<?> layer;
     private MapMode oldMapMode;
 
     /**
      * Constructs a new {@code ImageryAdjustAction} for the given layer.
      * @param layer The imagery layer
      */
-    public ImageryAdjustAction(ImageryLayer layer) {
+    public ImageryAdjustAction(AbstractTileSourceLayer<?> layer) {
         super(tr("New offset"), "adjustimg",
                 tr("Adjust the position of this imagery layer"), Main.map,
                 cursor);
@@ -66,8 +67,7 @@ public class ImageryAdjustAction extends MapMode implements AWTEventListener {
         if (!layer.isVisible()) {
             layer.setVisible(true);
         }
-        oldDx = layer.getDx();
-        oldDy = layer.getDy();
+        old = layer.getDisplaySettings().getDisplacement();
         addListeners();
         offsetDialog = new ImageryOffsetDialog();
         offsetDialog.setVisible(true);
@@ -88,7 +88,7 @@ public class ImageryAdjustAction extends MapMode implements AWTEventListener {
         super.exitMode();
         if (offsetDialog != null) {
             if (layer != null) {
-                layer.setOffset(oldDx, oldDy);
+                layer.getDisplaySettings().setDisplacement(old);
             }
             offsetDialog.setVisible(false);
             offsetDialog = null;
@@ -154,11 +154,9 @@ public class ImageryAdjustAction extends MapMode implements AWTEventListener {
     @Override
     public void mouseDragged(MouseEvent e) {
         if (layer == null || prevEastNorth == null) return;
-        EastNorth eastNorth =
-            Main.map.mapView.getEastNorth(e.getX(), e.getY());
-        double dx = layer.getDx()+eastNorth.east()-prevEastNorth.east();
-        double dy = layer.getDy()+eastNorth.north()-prevEastNorth.north();
-        layer.setOffset(dx, dy);
+        EastNorth eastNorth = Main.map.mapView.getEastNorth(e.getX(), e.getY());
+        EastNorth d = layer.getDisplaySettings().getDisplacement().add(eastNorth).subtract(prevEastNorth);
+        layer.getDisplaySettings().setDisplacement(d);
         if (offsetDialog != null) {
             offsetDialog.updateOffset();
         }
@@ -233,7 +231,7 @@ public class ImageryAdjustAction extends MapMode implements AWTEventListener {
                     String northing = ostr.substring(semicolon + 1).trim().replace(',', '.');
                     double dx = Double.parseDouble(easting);
                     double dy = Double.parseDouble(northing);
-                    layer.setOffset(dx, dy);
+                    layer.getDisplaySettings().setDisplacement(new EastNorth(dx, dy));
                 } catch (NumberFormatException nfe) {
                     // we repaint offset numbers in any case
                     if (Main.isTraceEnabled()) {
@@ -258,9 +256,10 @@ public class ImageryAdjustAction extends MapMode implements AWTEventListener {
             int precision = Main.getProjection().getDefaultZoomInPPD() >= 1.0 ? 2 : 7;
             // US locale to force decimal separator to be '.'
             try (Formatter us = new Formatter(Locale.US)) {
+                TileSourceDisplaySettings ds = layer.getDisplaySettings();
                 tOffset.setText(us.format(new StringBuilder()
                     .append("%1.").append(precision).append("f; %1.").append(precision).append('f').toString(),
-                    layer.getDx(), layer.getDy()).toString());
+                    ds.getDx(), ds.getDy()).toString());
             }
         }
 
@@ -297,7 +296,7 @@ public class ImageryAdjustAction extends MapMode implements AWTEventListener {
             offsetDialog = null;
             if (layer != null) {
                 if (getValue() != 1) {
-                    layer.setOffset(oldDx, oldDy);
+                    layer.getDisplaySettings().setDisplacement(old);
                 } else if (tBookmarkName.getText() != null && !tBookmarkName.getText().isEmpty()) {
                     OffsetBookmark.bookmarkOffset(tBookmarkName.getText(), layer);
                 }
diff --git a/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java b/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java
index 188eee6..9da2f7a 100644
--- a/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java
+++ b/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java
@@ -63,6 +63,7 @@ import org.openstreetmap.gui.jmapviewer.interfaces.TileLoaderListener;
 import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
 import org.openstreetmap.gui.jmapviewer.tilesources.AbstractTMSTileSource;
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.ImageryAdjustAction;
 import org.openstreetmap.josm.actions.RenameLayerAction;
 import org.openstreetmap.josm.actions.SaveActionBase;
 import org.openstreetmap.josm.data.Bounds;
@@ -164,6 +165,8 @@ implements ImageObserver, TileLoaderListener, ZoomChangeListener, FilterChangeLi
 
     private final TileSourceDisplaySettings displaySettings = createDisplaySettings();
 
+    private final ImageryAdjustAction adjustAction = new ImageryAdjustAction(this);
+
     /**
      * Creates Tile Source based Imagery Layer based on Imagery Info
      * @param info imagery info
@@ -285,15 +288,44 @@ implements ImageObserver, TileLoaderListener, ZoomChangeListener, FilterChangeLi
         if (isVisible()) Main.map.repaint();
     }
 
+
+    @Override
+    public double getDx() {
+        return getDisplaySettings().getDx();
+    }
+
+    @Override
+    public double getDy() {
+        return getDisplaySettings().getDy();
+    }
+
+    @Override
+    public void displace(double dx, double dy) {
+        getDisplaySettings().addDisplacement(new EastNorth(dx, dy));
+    }
+
     /**
      * Marks layer as needing redraw on offset change
      */
     @Override
     public void setOffset(double dx, double dy) {
-        super.setOffset(dx, dy);
-        needRedraw = true;
+        getDisplaySettings().setDisplacement(new EastNorth(dx, dy));
+    }
+
+    @Override
+    public Object getInfoComponent() {
+        JPanel panel = (JPanel) super.getInfoComponent();
+        EastNorth offset = getDisplaySettings().getDisplacement();
+        if (offset.distanceSq(0, 0) > 1e-10) {
+            panel.add(new JLabel(tr("Offset: ") + offset.east() + ';' + offset.north()), GBC.eol().insets(0, 5, 10, 0));
+        }
+        return panel;
     }
 
+    @Override
+    protected Action getAdjustAction() {
+        return adjustAction;
+    }
 
     /**
      * Returns average number of screen pixels per tile pixel for current mapview
@@ -1881,4 +1913,10 @@ implements ImageObserver, TileLoaderListener, ZoomChangeListener, FilterChangeLi
     public File createAndOpenSaveFileChooser() {
         return SaveActionBase.createAndOpenSaveFileChooser(tr("Save WMS file"), WMSLayerImporter.FILE_FILTER);
     }
+
+    @Override
+    public void destroy() {
+        super.destroy();
+        adjustAction.destroy();
+    }
 }
diff --git a/src/org/openstreetmap/josm/gui/layer/ImageryLayer.java b/src/org/openstreetmap/josm/gui/layer/ImageryLayer.java
index 8ff9166..6c539cc 100644
--- a/src/org/openstreetmap/josm/gui/layer/ImageryLayer.java
+++ b/src/org/openstreetmap/josm/gui/layer/ImageryLayer.java
@@ -15,6 +15,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 import javax.swing.AbstractAction;
+import javax.swing.Action;
 import javax.swing.Icon;
 import javax.swing.JCheckBoxMenuItem;
 import javax.swing.JComponent;
@@ -26,7 +27,6 @@ import javax.swing.JPopupMenu;
 import javax.swing.JSeparator;
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.actions.ImageryAdjustAction;
 import org.openstreetmap.josm.data.ProjectionBounds;
 import org.openstreetmap.josm.data.imagery.ImageryInfo;
 import org.openstreetmap.josm.data.imagery.OffsetBookmark;
@@ -34,6 +34,7 @@ import org.openstreetmap.josm.data.preferences.ColorProperty;
 import org.openstreetmap.josm.data.preferences.IntegerProperty;
 import org.openstreetmap.josm.gui.MenuScroller;
 import org.openstreetmap.josm.gui.layer.imagery.ImageryFilterSettings;
+import org.openstreetmap.josm.gui.layer.imagery.TileSourceDisplaySettings;
 import org.openstreetmap.josm.gui.widgets.UrlLabel;
 import org.openstreetmap.josm.tools.GBC;
 import org.openstreetmap.josm.tools.ImageProvider;
@@ -61,11 +62,6 @@ public abstract class ImageryLayer extends Layer {
 
     protected Icon icon;
 
-    protected double dx;
-    protected double dy;
-
-    private final ImageryAdjustAction adjustAction = new ImageryAdjustAction(this);
-
     private final ImageryFilterSettings filterSettings = new ImageryFilterSettings();
 
     /**
@@ -95,29 +91,51 @@ public abstract class ImageryLayer extends Layer {
         return Main.map.mapView.getWidth() / (bounds.maxEast - bounds.minEast);
     }
 
+    /**
+     * Gets the x displacement of this layer.
+     * To be removed end of 2016
+     * @return The x displacement.
+     * @deprecated Use {@link TileSourceDisplaySettings#getDx()}
+     */
+    @Deprecated
     public double getDx() {
-        return dx;
+        // moved to AbstractTileSourceLayer/TileSourceDisplaySettings. Remains until all actions migrate.
+        return 0;
     }
 
+    /**
+     * Gets the y displacement of this layer.
+     * To be removed end of 2016
+     * @return The y displacement.
+     * @deprecated Use {@link TileSourceDisplaySettings#getDy()}
+     */
+    @Deprecated
     public double getDy() {
-        return dy;
+        // moved to AbstractTileSourceLayer/TileSourceDisplaySettings. Remains until all actions migrate.
+        return 0;
     }
 
     /**
      * Sets the displacement offset of this layer. The layer is automatically invalidated.
+     * To be removed end of 2016
      * @param dx The x offset
      * @param dy The y offset
+     * @deprecated Use {@link TileSourceDisplaySettings}
      */
+    @Deprecated
     public void setOffset(double dx, double dy) {
-        this.dx = dx;
-        this.dy = dy;
-        invalidate();
+        // moved to AbstractTileSourceLayer/TileSourceDisplaySettings. Remains until all actions migrate.
     }
 
+    /**
+     * To be removed end of 2016
+     * @param dx
+     * @param dy
+     * @deprecated Use {@link TileSourceDisplaySettings}
+     */
+    @Deprecated
     public void displace(double dx, double dy) {
-        this.dx += dx;
-        this.dy += dy;
-        setOffset(this.dx, this.dy);
+        // moved to AbstractTileSourceLayer/TileSourceDisplaySettings. Remains until all actions migrate.
     }
 
     /**
@@ -152,9 +170,6 @@ public abstract class ImageryLayer extends Layer {
                 panel.add(new JLabel(tr("URL: ")), GBC.std().insets(0, 5, 2, 0));
                 panel.add(new UrlLabel(url), GBC.eol().insets(2, 5, 10, 0));
             }
-            if (dx != 0 || dy != 0) {
-                panel.add(new JLabel(tr("Offset: ") + dx + ';' + dy), GBC.eol().insets(0, 5, 10, 0));
-            }
         }
         return panel;
     }
@@ -215,7 +230,7 @@ public abstract class ImageryLayer extends Layer {
     }
 
     public JComponent getOffsetMenuItem(JComponent subMenu) {
-        JMenuItem adjustMenuItem = new JMenuItem(adjustAction);
+        JMenuItem adjustMenuItem = new JMenuItem(getAdjustAction());
         if (OffsetBookmark.allBookmarks.isEmpty()) return adjustMenuItem;
 
         subMenu.add(adjustMenuItem);
@@ -227,7 +242,7 @@ public abstract class ImageryLayer extends Layer {
                 continue;
             }
             JCheckBoxMenuItem item = new JCheckBoxMenuItem(new ApplyOffsetAction(b));
-            if (Utils.equalsEpsilon(b.dx, dx) && Utils.equalsEpsilon(b.dy, dy)) {
+            if (Utils.equalsEpsilon(b.dx, getDx()) && Utils.equalsEpsilon(b.dy, getDy())) {
                 item.setSelected(true);
             }
             subMenu.add(item);
@@ -244,6 +259,8 @@ public abstract class ImageryLayer extends Layer {
         return hasBookmarks ? subMenu : adjustMenuItem;
     }
 
+    protected abstract Action getAdjustAction();
+
     /**
      * Gets the settings for the filter that is applied to this layer.
      * @return The filter settings.
@@ -313,10 +330,4 @@ public abstract class ImageryLayer extends Layer {
         }
         return img;
     }
-
-    @Override
-    public void destroy() {
-        super.destroy();
-        adjustAction.destroy();
-    }
 }
diff --git a/src/org/openstreetmap/josm/gui/layer/imagery/TileSourceDisplaySettings.java b/src/org/openstreetmap/josm/gui/layer/imagery/TileSourceDisplaySettings.java
index 196fbac..d534b36 100644
--- a/src/org/openstreetmap/josm/gui/layer/imagery/TileSourceDisplaySettings.java
+++ b/src/org/openstreetmap/josm/gui/layer/imagery/TileSourceDisplaySettings.java
@@ -6,8 +6,11 @@ import java.util.concurrent.CopyOnWriteArrayList;
 
 import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.preferences.BooleanProperty;
 import org.openstreetmap.josm.gui.layer.AbstractTileSourceLayer;
+import org.openstreetmap.josm.tools.CheckParameterUtil;
+import org.openstreetmap.josm.tools.bugreport.BugReport;
 
 /**
  * This are the preferences of how to display a {@link TileSource}.
@@ -35,6 +38,8 @@ public class TileSourceDisplaySettings {
      */
     private static final String SHOW_ERRORS = "show-errors";
 
+    private static final String DISPLACEMENT = "displacement";
+
     private static final String PREFERENCE_PREFIX = "imagery.generic";
 
     /**
@@ -47,6 +52,7 @@ public class TileSourceDisplaySettings {
      */
     public static final BooleanProperty PROP_AUTO_ZOOM = new BooleanProperty(PREFERENCE_PREFIX + ".default_autozoom", true);
 
+
     /** if layers changes automatically, when user zooms in */
     private boolean autoZoom;
     /** if layer automatically loads new tiles */
@@ -54,6 +60,11 @@ public class TileSourceDisplaySettings {
     /** if layer should show errors on tiles */
     private boolean showErrors;
 
+    /**
+     * The displacement
+     */
+    private EastNorth displacement = new EastNorth(0, 0);
+
     private final CopyOnWriteArrayList<DisplaySettingsChangeListener> listeners = new CopyOnWriteArrayList<>();
 
     /**
@@ -149,8 +160,57 @@ public class TileSourceDisplaySettings {
     }
 
     /**
+     * Gets the displacement in x (east) direction
+     * @return The displacement.
+     * @since xxx
+     */
+    public double getDx() {
+        return displacement.east();
+    }
+
+    /**
+     * Gets the displacement in y (north) direction
+     * @return The displacement.
+     * @since xxx
+     */
+    public double getDy() {
+        return displacement.north();
+    }
+
+    /**
+     * Gets the displacement of the image
+     * @return The displacement.
+     * @since xxx
+     */
+    public EastNorth getDisplacement() {
+        return displacement;
+    }
+
+    /**
+     * Set the displacement
+     * @param displacement The new displacement
+     * @since xxx
+     */
+    public void setDisplacement(EastNorth displacement) {
+        CheckParameterUtil.ensureValidCoordinates(displacement, "displacement");
+        this.displacement = displacement;
+        fireSettingsChange(DISPLACEMENT);
+    }
+
+    /**
+     * Adds the given value to the displacement.
+     * @param displacement The value to add.
+     * @since xxx
+     */
+    public void addDisplacement(EastNorth displacement) {
+        CheckParameterUtil.ensureValidCoordinates(displacement, "displacement");
+        setDisplacement(this.displacement.add(displacement));
+    }
+
+    /**
      * Notifies all listeners that the paint settings have changed
      * @param changedSetting The setting name
+     * @since xxx
      */
     private void fireSettingsChange(String changedSetting) {
         DisplaySettingsChangeEvent e = new DisplaySettingsChangeEvent(changedSetting);
@@ -184,6 +244,8 @@ public class TileSourceDisplaySettings {
         data.put(AUTO_LOAD, Boolean.toString(autoLoad));
         data.put(AUTO_ZOOM, Boolean.toString(autoZoom));
         data.put(SHOW_ERRORS, Boolean.toString(showErrors));
+        data.put("dx", String.valueOf(getDx()));
+        data.put("dy", String.valueOf(getDy()));
     }
 
     /**
@@ -192,19 +254,29 @@ public class TileSourceDisplaySettings {
      * @see #storeTo(Map)
      */
     public void loadFrom(Map<String, String> data) {
-        String doAutoLoad = data.get(AUTO_LOAD);
-        if (doAutoLoad != null) {
-            setAutoLoad(Boolean.parseBoolean(doAutoLoad));
-        }
+        try {
+            String doAutoLoad = data.get(AUTO_LOAD);
+            if (doAutoLoad != null) {
+                setAutoLoad(Boolean.parseBoolean(doAutoLoad));
+            }
 
-        String doAutoZoom = data.get(AUTO_ZOOM);
-        if (doAutoZoom != null) {
-            setAutoZoom(Boolean.parseBoolean(doAutoZoom));
-        }
+            String doAutoZoom = data.get(AUTO_ZOOM);
+            if (doAutoZoom != null) {
+                setAutoZoom(Boolean.parseBoolean(doAutoZoom));
+            }
+
+            String doShowErrors = data.get(SHOW_ERRORS);
+            if (doShowErrors != null) {
+                setShowErrors(Boolean.parseBoolean(doShowErrors));
+            }
 
-        String doShowErrors = data.get(SHOW_ERRORS);
-        if (doShowErrors != null) {
-            setShowErrors(Boolean.parseBoolean(doShowErrors));
+            String dx = data.get("dx");
+            String dy = data.get("dy");
+            if (dx != null && dy != null) {
+                setDisplacement(new EastNorth(Double.parseDouble(dx), Double.parseDouble(dy)));
+            }
+        } catch (RuntimeException e) {
+            throw BugReport.intercept(e).put("data", data);
         }
     }
 
diff --git a/src/org/openstreetmap/josm/io/session/ImagerySessionImporter.java b/src/org/openstreetmap/josm/io/session/ImagerySessionImporter.java
index 2b68c71..df5f135 100644
--- a/src/org/openstreetmap/josm/io/session/ImagerySessionImporter.java
+++ b/src/org/openstreetmap/josm/io/session/ImagerySessionImporter.java
@@ -53,9 +53,6 @@ public class ImagerySessionImporter implements SessionLayerImporter {
             AbstractTileSourceLayer<?> tsLayer = (AbstractTileSourceLayer<?>) layer;
             tsLayer.getDisplaySettings().loadFrom(attributes);
         }
-        if (attributes.containsKey("dx") && attributes.containsKey("dy")) {
-            layer.setOffset(Double.parseDouble(attributes.get("dx")), Double.parseDouble(attributes.get("dy")));
-        }
         return layer;
     }
 }
diff --git a/test/unit/org/openstreetmap/josm/io/session/SessionReaderTest.java b/test/unit/org/openstreetmap/josm/io/session/SessionReaderTest.java
index d2216ef..87bf617 100644
--- a/test/unit/org/openstreetmap/josm/io/session/SessionReaderTest.java
+++ b/test/unit/org/openstreetmap/josm/io/session/SessionReaderTest.java
@@ -14,6 +14,7 @@ import org.junit.Test;
 import org.openstreetmap.josm.JOSMFixture;
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.TestUtils;
+import org.openstreetmap.josm.gui.layer.AbstractTileSourceLayer;
 import org.openstreetmap.josm.gui.layer.GpxLayer;
 import org.openstreetmap.josm.gui.layer.ImageryLayer;
 import org.openstreetmap.josm.gui.layer.Layer;
@@ -124,10 +125,10 @@ public class SessionReaderTest {
         final List<Layer> layers = testRead("bing.jos");
         assertEquals(layers.size(), 1);
         assertTrue(layers.get(0) instanceof ImageryLayer);
-        final ImageryLayer image = (ImageryLayer) layers.get(0);
+        final AbstractTileSourceLayer<?> image = (AbstractTileSourceLayer<?>) layers.get(0);
         assertEquals("Bing aerial imagery", image.getName());
-        assertEquals(image.getDx(), 12.34, 1e-9);
-        assertEquals(image.getDy(), -56.78, 1e-9);
+        assertEquals(image.getDisplaySettings().getDx(), 12.34, 1e-9);
+        assertEquals(image.getDisplaySettings().getDy(), -56.78, 1e-9);
     }
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/io/session/SessionWriterTest.java b/test/unit/org/openstreetmap/josm/io/session/SessionWriterTest.java
index 3cb237c..f1c922a 100644
--- a/test/unit/org/openstreetmap/josm/io/session/SessionWriterTest.java
+++ b/test/unit/org/openstreetmap/josm/io/session/SessionWriterTest.java
@@ -14,6 +14,7 @@ import java.util.Map;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.openstreetmap.josm.JOSMFixture;
+import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.gpx.GpxData;
 import org.openstreetmap.josm.data.gpx.WayPoint;
@@ -135,8 +136,8 @@ public class SessionWriterTest {
     }
 
     private ImageryLayer createImageryLayer() {
-        ImageryLayer layer = new TMSLayer(new ImageryInfo("the name", "http://www.url.com/"));
-        layer.setOffset(12, 34);
+        TMSLayer layer = new TMSLayer(new ImageryInfo("the name", "http://www.url.com/"));
+        layer.getDisplaySettings().setDisplacement(new EastNorth(12, 34));
         return layer;
     }
 
