Index: /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/AbstractMapRenderer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/AbstractMapRenderer.java	(revision 13809)
+++ /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/AbstractMapRenderer.java	(revision 13810)
@@ -10,8 +10,7 @@
 
 import org.openstreetmap.josm.data.osm.BBox;
-import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.INode;
-import org.openstreetmap.josm.data.osm.Node;
-import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.osm.IWay;
+import org.openstreetmap.josm.data.osm.OsmData;
 import org.openstreetmap.josm.data.osm.WaySegment;
 import org.openstreetmap.josm.gui.MapViewState;
@@ -127,11 +126,12 @@
      * @param data The data set being rendered.
      * @param bbox The bounding box being displayed.
-     */
-    public void drawVirtualNodes(DataSet data, BBox bbox) {
+     * @since 13810 (signature)
+     */
+    public void drawVirtualNodes(OsmData<?, ?, ?, ?> data, BBox bbox) {
         if (virtualNodeSize == 0 || data == null || bbox == null || data.isLocked())
             return;
         // print normal virtual nodes
         GeneralPath path = new GeneralPath();
-        for (Way osm : data.searchWays(bbox)) {
+        for (IWay<?> osm : data.searchWays(bbox)) {
             if (osm.isUsable() && !osm.isDisabledAndHidden() && !osm.isDisabled()) {
                 visitVirtual(path, osm);
@@ -222,10 +222,11 @@
      * @param w The ways to draw node for.
      * @since 10827
-     */
-    public void visitVirtual(Path2D path, Way w) {
-        Iterator<Node> it = w.getNodes().iterator();
+     * @since 13810 (signature)
+     */
+    public void visitVirtual(Path2D path, IWay<?> w) {
+        Iterator<? extends INode> it = w.getNodes().iterator();
         MapViewPoint lastP = null;
         while (it.hasNext()) {
-            Node n = it.next();
+            INode n = it.next();
             if (n.isLatLonKnown()) {
                 MapViewPoint p = mapState.getPointFor(n);
Index: /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/ComputeStyleListWorker.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/ComputeStyleListWorker.java	(revision 13809)
+++ /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/ComputeStyleListWorker.java	(revision 13810)
@@ -8,9 +8,9 @@
 import java.util.concurrent.RecursiveTask;
 
-import org.openstreetmap.josm.data.osm.Node;
-import org.openstreetmap.josm.data.osm.OsmPrimitive;
-import org.openstreetmap.josm.data.osm.Relation;
-import org.openstreetmap.josm.data.osm.Way;
-import org.openstreetmap.josm.data.osm.visitor.OsmPrimitiveVisitor;
+import org.openstreetmap.josm.data.osm.INode;
+import org.openstreetmap.josm.data.osm.IPrimitive;
+import org.openstreetmap.josm.data.osm.IRelation;
+import org.openstreetmap.josm.data.osm.IWay;
+import org.openstreetmap.josm.data.osm.visitor.PrimitiveVisitor;
 import org.openstreetmap.josm.data.osm.visitor.paint.StyledMapRenderer.StyleRecord;
 import org.openstreetmap.josm.gui.NavigatableComponent;
@@ -32,6 +32,6 @@
  * @since 11914 (extracted from StyledMapRenderer)
  */
-public class ComputeStyleListWorker extends RecursiveTask<List<StyleRecord>> implements OsmPrimitiveVisitor {
-    private final transient List<? extends OsmPrimitive> input;
+public class ComputeStyleListWorker extends RecursiveTask<List<StyleRecord>> implements PrimitiveVisitor {
+    private final transient List<? extends IPrimitive> input;
     private final transient List<StyleRecord> output;
 
@@ -52,7 +52,8 @@
      * @param output the list of styles to which styles will be added
      * @param directExecutionTaskSize the threshold deciding whether to subdivide the tasks
+     * @since 13810 (signature)
      */
     ComputeStyleListWorker(double circum, NavigatableComponent nc,
-            final List<? extends OsmPrimitive> input, List<StyleRecord> output, int directExecutionTaskSize) {
+            final List<? extends IPrimitive> input, List<StyleRecord> output, int directExecutionTaskSize) {
         this(circum, nc, input, output, directExecutionTaskSize, MapPaintStyles.getStyles());
     }
@@ -67,7 +68,8 @@
      * @param styles the {@link ElemStyles} instance used to generate primitive {@link StyleElement}s.
      * @since 12964
+     * @since 13810 (signature)
      */
     ComputeStyleListWorker(double circum, NavigatableComponent nc,
-            final List<? extends OsmPrimitive> input, List<StyleRecord> output, int directExecutionTaskSize,
+            final List<? extends IPrimitive> input, List<StyleRecord> output, int directExecutionTaskSize,
             ElemStyles styles) {
         this.circum = circum;
@@ -108,5 +110,5 @@
         MapCSSStyleSource.STYLE_SOURCE_LOCK.readLock().lock();
         try {
-            for (final OsmPrimitive osm : input) {
+            for (final IPrimitive osm : input) {
                 acceptDrawable(osm);
             }
@@ -119,5 +121,5 @@
     }
 
-    private void acceptDrawable(final OsmPrimitive osm) {
+    private void acceptDrawable(final IPrimitive osm) {
         try {
             if (osm.isDrawable()) {
@@ -130,15 +132,15 @@
 
     @Override
-    public void visit(Node n) {
+    public void visit(INode n) {
         add(n, StyledMapRenderer.computeFlags(n, false));
     }
 
     @Override
-    public void visit(Way w) {
+    public void visit(IWay<?> w) {
         add(w, StyledMapRenderer.computeFlags(w, true));
     }
 
     @Override
-    public void visit(Relation r) {
+    public void visit(IRelation<?> r) {
         add(r, StyledMapRenderer.computeFlags(r, true));
     }
@@ -148,6 +150,7 @@
      * @param osm node
      * @param flags flags
+     * @since 13810 (signature)
      */
-    public void add(Node osm, int flags) {
+    public void add(INode osm, int flags) {
         StyleElementList sl = styles.get(osm, circum, nc);
         for (StyleElement s : sl) {
@@ -160,6 +163,7 @@
      * @param osm way
      * @param flags flags
+     * @since 13810 (signature)
      */
-    public void add(Way osm, int flags) {
+    public void add(IWay<?> osm, int flags) {
         StyleElementList sl = styles.get(osm, circum, nc);
         for (StyleElement s : sl) {
@@ -174,6 +178,7 @@
      * @param osm relation
      * @param flags flags
+     * @since 13810 (signature)
      */
-    public void add(Relation osm, int flags) {
+    public void add(IRelation<?> osm, int flags) {
         StyleElementList sl = styles.get(osm, circum, nc);
         for (StyleElement s : sl) {
Index: /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/Rendering.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/Rendering.java	(revision 13809)
+++ /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/Rendering.java	(revision 13810)
@@ -3,8 +3,8 @@
 
 import org.openstreetmap.josm.data.Bounds;
-import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.OsmData;
 
 /**
- * <p>An object which can render data provided by a {@link DataSet}.</p>
+ * <p>An object which can render data provided by a {@link OsmData}.</p>
  * @since  4087 (creation)
  * @since 10600 (functional interface)
@@ -19,5 +19,6 @@
      * @param bbox the bounding box for the data to be rendered. Only objects within or intersecting
      * with {@code bbox} are rendered
+     * @since 13810 (signature)
      */
-    void render(DataSet data, boolean renderVirtualNodes, Bounds bbox);
+    void render(OsmData<?, ?, ?, ?> data, boolean renderVirtualNodes, Bounds bbox);
 }
Index: /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java	(revision 13809)
+++ /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java	(revision 13810)
@@ -46,8 +46,10 @@
 import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.osm.BBox;
-import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.INode;
 import org.openstreetmap.josm.data.osm.IPrimitive;
+import org.openstreetmap.josm.data.osm.IRelation;
+import org.openstreetmap.josm.data.osm.IWay;
 import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmData;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.OsmUtils;
@@ -113,9 +115,9 @@
     public static class StyleRecord implements Comparable<StyleRecord> {
         private final StyleElement style;
-        private final OsmPrimitive osm;
+        private final IPrimitive osm;
         private final int flags;
         private final long order;
 
-        StyleRecord(StyleElement style, OsmPrimitive osm, int flags) {
+        StyleRecord(StyleElement style, IPrimitive osm, int flags) {
             this.style = style;
             this.osm = osm;
@@ -1587,5 +1589,5 @@
 
     @Override
-    public void render(final DataSet data, boolean renderVirtualNodes, Bounds bounds) {
+    public void render(final OsmData<?, ?, ?, ?> data, boolean renderVirtualNodes, Bounds bounds) {
         RenderBenchmarkCollector benchmark = benchmarkFactory.get();
         BBox bbox = bounds.toBBox();
@@ -1607,5 +1609,5 @@
     }
 
-    private void paintWithLock(final DataSet data, boolean renderVirtualNodes, RenderBenchmarkCollector benchmark,
+    private void paintWithLock(final OsmData<?, ?, ?, ?> data, boolean renderVirtualNodes, RenderBenchmarkCollector benchmark,
             BBox bbox) {
         try {
@@ -1614,7 +1616,7 @@
             benchmark.renderStart(circum);
 
-            List<Node> nodes = data.searchNodes(bbox);
-            List<Way> ways = data.searchWays(bbox);
-            List<Relation> relations = data.searchRelations(bbox);
+            List<? extends INode> nodes = data.searchNodes(bbox);
+            List<? extends IWay<?>> ways = data.searchWays(bbox);
+            List<? extends IRelation<?>> relations = data.searchRelations(bbox);
 
             final List<StyleRecord> allStyleElems = new ArrayList<>(nodes.size()+ways.size()+relations.size());
Index: /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/WireframeMapRenderer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/WireframeMapRenderer.java	(revision 13809)
+++ /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/WireframeMapRenderer.java	(revision 13810)
@@ -18,13 +18,12 @@
 import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.osm.BBox;
-import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.INode;
-import org.openstreetmap.josm.data.osm.Node;
-import org.openstreetmap.josm.data.osm.OsmPrimitive;
-import org.openstreetmap.josm.data.osm.Relation;
-import org.openstreetmap.josm.data.osm.RelationMember;
-import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.osm.IPrimitive;
+import org.openstreetmap.josm.data.osm.IRelation;
+import org.openstreetmap.josm.data.osm.IRelationMember;
+import org.openstreetmap.josm.data.osm.IWay;
+import org.openstreetmap.josm.data.osm.OsmData;
 import org.openstreetmap.josm.data.osm.WaySegment;
-import org.openstreetmap.josm.data.osm.visitor.OsmPrimitiveVisitor;
+import org.openstreetmap.josm.data.osm.visitor.PrimitiveVisitor;
 import org.openstreetmap.josm.gui.MapViewState.MapViewPoint;
 import org.openstreetmap.josm.gui.MapViewState.MapViewRectangle;
@@ -39,5 +38,5 @@
  * @since 23
  */
-public class WireframeMapRenderer extends AbstractMapRenderer implements OsmPrimitiveVisitor {
+public class WireframeMapRenderer extends AbstractMapRenderer implements PrimitiveVisitor {
 
     /** Color Preference for ways not matching any other group */
@@ -84,14 +83,9 @@
     /** Path store to draw subsequent segments of same color as one <code>Path</code>. */
     protected MapPath2D currentPath = new MapPath2D();
-    /**
-      * <code>DataSet</code> passed to the @{link render} function to overcome the argument
-      * limitations of @{link Visitor} interface. Only valid until end of rendering call.
-      */
-    private DataSet ds;
 
     /** Helper variable for {@link #drawSegment} */
     private static final ArrowPaintHelper ARROW_PAINT_HELPER = new ArrowPaintHelper(Utils.toRadians(20), 10);
 
-    /** Helper variable for {@link #visit(Relation)} */
+    /** Helper variable for {@link #visit(IRelation)} */
     private final Stroke relatedWayStroke = new BasicStroke(
             4, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_BEVEL);
@@ -153,7 +147,6 @@
 
     @Override
-    public void render(DataSet data, boolean virtual, Bounds bounds) {
+    public void render(OsmData<?, ?, ?, ?> data, boolean virtual, Bounds bounds) {
         BBox bbox = bounds.toBBox();
-        this.ds = data;
         Rectangle clip = g.getClipBounds();
         clip.grow(50, 50);
@@ -161,6 +154,6 @@
         getSettings(virtual);
 
-        for (final Relation rel : data.searchRelations(bbox)) {
-            if (rel.isDrawable() && !ds.isSelected(rel) && !rel.isDisabledAndHidden()) {
+        for (final IRelation<?> rel : data.searchRelations(bbox)) {
+            if (rel.isDrawable() && !rel.isSelected() && !rel.isDisabledAndHidden()) {
                 rel.accept(this);
             }
@@ -168,9 +161,9 @@
 
         // draw tagged ways first, then untagged ways, then highlighted ways
-        List<Way> highlightedWays = new ArrayList<>();
-        List<Way> untaggedWays = new ArrayList<>();
-
-        for (final Way way : data.searchWays(bbox)) {
-            if (way.isDrawable() && !ds.isSelected(way) && !way.isDisabledAndHidden()) {
+        List<IWay<?>> highlightedWays = new ArrayList<>();
+        List<IWay<?>> untaggedWays = new ArrayList<>();
+
+        for (final IWay<?> way : data.searchWays(bbox)) {
+            if (way.isDrawable() && !way.isSelected() && !way.isDisabledAndHidden()) {
                 if (way.isHighlighted()) {
                     highlightedWays.add(way);
@@ -185,7 +178,7 @@
 
         // Display highlighted ways after the other ones (fix #8276)
-        List<Way> specialWays = new ArrayList<>(untaggedWays);
+        List<IWay<?>> specialWays = new ArrayList<>(untaggedWays);
         specialWays.addAll(highlightedWays);
-        for (final Way way : specialWays) {
+        for (final IWay<?> way : specialWays) {
             way.accept(this);
         }
@@ -193,5 +186,5 @@
         displaySegments();
 
-        for (final OsmPrimitive osm : data.getSelected()) {
+        for (final IPrimitive osm : data.getSelected()) {
             if (osm.isDrawable()) {
                 osm.accept(this);
@@ -200,6 +193,6 @@
         displaySegments();
 
-        for (final OsmPrimitive osm: data.searchNodes(bbox)) {
-            if (osm.isDrawable() && !ds.isSelected(osm) && !osm.isDisabledAndHidden()) {
+        for (final INode osm: data.searchNodes(bbox)) {
+            if (osm.isDrawable() && !osm.isSelected() && !osm.isDisabledAndHidden()) {
                 osm.accept(this);
             }
@@ -237,5 +230,5 @@
      */
     @Override
-    public void visit(Node n) {
+    public void visit(INode n) {
         if (n.isIncomplete()) return;
 
@@ -265,10 +258,10 @@
             }
 
-            final int size = max(ds.isSelected(n) ? selectedNodeSize : 0,
+            final int size = max(n.isSelected() ? selectedNodeSize : 0,
                     isNodeTagged(n) ? taggedNodeSize : 0,
                     n.isConnectionNode() ? connectionNodeSize : 0,
                     unselectedNodeSize);
 
-            final boolean fill = (ds.isSelected(n) && fillSelectedNode) ||
+            final boolean fill = (n.isSelected() && fillSelectedNode) ||
             (isNodeTagged(n) && fillTaggedNode) ||
             (n.isConnectionNode() && fillConnectionNode) ||
@@ -279,5 +272,5 @@
     }
 
-    private static boolean isNodeTagged(Node n) {
+    private static boolean isNodeTagged(INode n) {
         return n.isTagged() || n.isAnnotated();
     }
@@ -288,5 +281,5 @@
      */
     @Override
-    public void visit(Way w) {
+    public void visit(IWay<?> w) {
         if (w.isIncomplete() || w.getNodesCount() < 2)
             return;
@@ -295,8 +288,8 @@
            (even if the tag is negated as in oneway=false) or the way is selected */
 
-        boolean showThisDirectionArrow = ds.isSelected(w) || showDirectionArrow;
+        boolean showThisDirectionArrow = w.isSelected() || showDirectionArrow;
         /* head only takes over control if the option is true,
            the direction should be shown at all and not only because it's selected */
-        boolean showOnlyHeadArrowOnly = showThisDirectionArrow && showHeadArrowOnly && !ds.isSelected(w);
+        boolean showOnlyHeadArrowOnly = showThisDirectionArrow && showHeadArrowOnly && !w.isSelected();
         Color wayColor;
 
@@ -315,5 +308,5 @@
         }
 
-        Iterator<Node> it = w.getNodes().iterator();
+        Iterator<? extends INode> it = w.getNodes().iterator();
         if (it.hasNext()) {
             MapViewPoint lastP = mapState.getPointFor(it.next());
@@ -340,5 +333,5 @@
      */
     @Override
-    public void visit(Relation r) {
+    public void visit(IRelation<?> r) {
         if (r.isIncomplete()) return;
 
@@ -355,5 +348,5 @@
         g.setColor(col);
 
-        for (RelationMember m : r.getMembers()) {
+        for (IRelationMember<?> m : r.getMembers()) {
             if (m.getMember().isIncomplete() || !m.getMember().isDrawable()) {
                 continue;
@@ -361,5 +354,5 @@
 
             if (m.isNode()) {
-                MapViewPoint p = mapState.getPointFor(m.getNode());
+                MapViewPoint p = mapState.getPointFor((INode) m.getMember());
                 if (p.isInView()) {
                     g.draw(new Ellipse2D.Double(p.getInViewX()-4, p.getInViewY()-4, 9, 9));
@@ -370,5 +363,5 @@
 
                 boolean first = true;
-                for (Node n : m.getWay().getNodes()) {
+                for (INode n : ((IWay<?>) m.getMember()).getNodes()) {
                     if (!n.isDrawable()) {
                         continue;
Index: /trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java	(revision 13809)
+++ /trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java	(revision 13810)
@@ -582,6 +582,6 @@
                 final String description2 = group == null ? null : description;
                 final List<OsmPrimitive> primitives;
-                if (env.child != null) {
-                    primitives = Arrays.asList(p, env.child);
+                if (env.child instanceof OsmPrimitive) {
+                    primitives = Arrays.asList(p, (OsmPrimitive) env.child);
                 } else {
                     primitives = Collections.singletonList(p);
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java	(revision 13809)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java	(revision 13810)
@@ -12,6 +12,6 @@
 import java.util.Optional;
 
+import org.openstreetmap.josm.data.osm.IPrimitive;
 import org.openstreetmap.josm.data.osm.Node;
-import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Relation;
 import org.openstreetmap.josm.data.osm.Way;
@@ -45,11 +45,11 @@
  * There are several steps to derive the list of elements for display:
  * <ol>
- * <li>{@link #generateStyles(OsmPrimitive, double, boolean)} applies the
+ * <li>{@link #generateStyles(IPrimitive, double, boolean)} applies the
  * {@link StyleSource}s one after another to get a key-value map of MapCSS
  * properties. Then a preliminary set of StyleElements is derived from the
  * properties map.</li>
- * <li>{@link #getImpl(OsmPrimitive, double, NavigatableComponent)} handles the
+ * <li>{@link #getImpl(IPrimitive, double, NavigatableComponent)} handles the
  * different forms of multipolygon tagging.</li>
- * <li>{@link #getStyleCacheWithRange(OsmPrimitive, double, NavigatableComponent)}
+ * <li>{@link #getStyleCacheWithRange(IPrimitive, double, NavigatableComponent)}
  * adds a default StyleElement for primitives that would be invisible otherwise.
  * (For example untagged nodes and ways.)</li>
@@ -131,6 +131,7 @@
      * @param nc display component
      * @return list of styles
-     */
-    public StyleElementList get(OsmPrimitive osm, double scale, NavigatableComponent nc) {
+     * @since 13810 (signature)
+     */
+    public StyleElementList get(IPrimitive osm, double scale, NavigatableComponent nc) {
         return getStyleCacheWithRange(osm, scale, nc).a;
     }
@@ -145,6 +146,7 @@
      * @param nc navigatable component
      * @return pair containing style list and range
-     */
-    public Pair<StyleElementList, Range> getStyleCacheWithRange(OsmPrimitive osm, double scale, NavigatableComponent nc) {
+     * @since 13810 (signature)
+     */
+    public Pair<StyleElementList, Range> getStyleCacheWithRange(IPrimitive osm, double scale, NavigatableComponent nc) {
         if (!osm.isCachedStyleUpToDate() || scale <= 0) {
             osm.setCachedStyle(StyleCache.EMPTY_STYLECACHE);
@@ -232,5 +234,5 @@
      * @return pair containing style list and range
      */
-    private Pair<StyleElementList, Range> getImpl(OsmPrimitive osm, double scale, NavigatableComponent nc) {
+    private Pair<StyleElementList, Range> getImpl(IPrimitive osm, double scale, NavigatableComponent nc) {
         if (osm instanceof Node)
             return generateStyles(osm, scale, false);
@@ -242,5 +244,5 @@
 
             // FIXME: Maybe in the future outer way styles apply to outers ignoring the multipolygon?
-            for (OsmPrimitive referrer : osm.getReferrers()) {
+            for (IPrimitive referrer : osm.getReferrers()) {
                 Relation r = (Relation) referrer;
                 if (!drawMultipolygon || !r.isMultipolygon() || !r.isUsable()) {
@@ -310,5 +312,5 @@
             if (!isDefaultLines()) return p;
 
-            for (OsmPrimitive referrer : osm.getReferrers()) {
+            for (IPrimitive referrer : osm.getReferrers()) {
                 Relation ref = (Relation) referrer;
                 if (!drawMultipolygon || !ref.isMultipolygon() || !ref.isUsable()) {
@@ -362,6 +364,7 @@
      * outer ways of a multipolygon.
      * @return the generated styles and the valid range as a pair
-     */
-    public Pair<StyleElementList, Range> generateStyles(OsmPrimitive osm, double scale, boolean pretendWayIsClosed) {
+     * @since 13810 (signature)
+     */
+    public Pair<StyleElementList, Range> generateStyles(IPrimitive osm, double scale, boolean pretendWayIsClosed) {
 
         List<StyleElement> sl = new ArrayList<>();
@@ -522,6 +525,7 @@
      * outer ways of a multipolygon.
      * @return first AreaElement found or {@code null}.
-     */
-    public static AreaElement getAreaElemStyle(OsmPrimitive p, boolean pretendWayIsClosed) {
+     * @since 13810 (signature)
+     */
+    public static AreaElement getAreaElemStyle(IPrimitive p, boolean pretendWayIsClosed) {
         MapCSSStyleSource.STYLE_SOURCE_LOCK.readLock().lock();
         try {
@@ -545,6 +549,7 @@
      * outer ways of a multipolygon.
      * @return {@code true} if primitive has an AreaElement
-     */
-    public static boolean hasAreaElemStyle(OsmPrimitive p, boolean pretendWayIsClosed) {
+     * @since 13810 (signature)
+     */
+    public static boolean hasAreaElemStyle(IPrimitive p, boolean pretendWayIsClosed) {
         return getAreaElemStyle(p, pretendWayIsClosed) != null;
     }
@@ -558,6 +563,7 @@
      * @return {@code true} if primitive has area elements, but no line elements
      * @since 12700
-     */
-    public static boolean hasOnlyAreaElements(OsmPrimitive p) {
+     * @since 13810 (signature)
+     */
+    public static boolean hasOnlyAreaElements(IPrimitive p) {
         MapCSSStyleSource.STYLE_SOURCE_LOCK.readLock().lock();
         try {
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/Environment.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/Environment.java	(revision 13809)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/Environment.java	(revision 13810)
@@ -2,5 +2,5 @@
 package org.openstreetmap.josm.gui.mappaint;
 
-import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.IPrimitive;
 import org.openstreetmap.josm.data.osm.Relation;
 import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.Context;
@@ -18,5 +18,5 @@
      * The primitive that is currently evaluated
      */
-    public OsmPrimitive osm;
+    public IPrimitive osm;
 
     /**
@@ -43,10 +43,10 @@
      * is evaluated in a {@link LinkSelector} (within a child selector)
      */
-    public OsmPrimitive parent;
+    public IPrimitive parent;
 
     /**
      * The same for parent selector. Only one of the 2 fields (parent or child) is not null in any environment.
      */
-    public OsmPrimitive child;
+    public IPrimitive child;
 
     /**
@@ -71,6 +71,7 @@
      * @param osm OSM primitive
      * @since 8415
-     */
-    public Environment(OsmPrimitive osm) {
+     * @since 13810 (signature)
+     */
+    public Environment(IPrimitive osm) {
         this.osm = osm;
     }
@@ -82,6 +83,7 @@
      * @param layer layer
      * @param source style source
-     */
-    public Environment(OsmPrimitive osm, MultiCascade mc, String layer, StyleSource source) {
+     * @since 13810 (signature)
+     */
+    public Environment(IPrimitive osm, MultiCascade mc, String layer, StyleSource source) {
         this.osm = osm;
         this.mc = mc;
@@ -114,6 +116,7 @@
      * @return A clone of this environment, with the specified primitive
      * @see #osm
-     */
-    public Environment withPrimitive(OsmPrimitive osm) {
+     * @since 13810 (signature)
+     */
+    public Environment withPrimitive(IPrimitive osm) {
         Environment e = new Environment(this);
         e.osm = osm;
@@ -126,6 +129,7 @@
      * @return A clone of this environment, with the specified parent
      * @see #parent
-     */
-    public Environment withParent(OsmPrimitive parent) {
+     * @since 13810 (signature)
+     */
+    public Environment withParent(IPrimitive parent) {
         Environment e = new Environment(this);
         e.parent = parent;
@@ -142,6 +146,7 @@
      * @see #index
      * @since 6175
-     */
-    public Environment withParentAndIndexAndLinkContext(OsmPrimitive parent, int index, int count) {
+     * @since 13810 (signature)
+     */
+    public Environment withParentAndIndexAndLinkContext(IPrimitive parent, int index, int count) {
         Environment e = new Environment(this);
         e.parent = parent;
@@ -157,6 +162,7 @@
      * @return A clone of this environment, with the specified child
      * @see #child
-     */
-    public Environment withChild(OsmPrimitive child) {
+     * @since 13810 (signature)
+     */
+    public Environment withChild(IPrimitive child) {
         Environment e = new Environment(this);
         e.child = child;
@@ -173,6 +179,7 @@
      * @see #index
      * @since 6175
-     */
-    public Environment withChildAndIndexAndLinkContext(OsmPrimitive child, int index, int count) {
+     * @since 13810 (signature)
+     */
+    public Environment withChildAndIndexAndLinkContext(IPrimitive child, int index, int count) {
         Environment e = new Environment(this);
         e.child = child;
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/StyleSource.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/StyleSource.java	(revision 13809)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/StyleSource.java	(revision 13810)
@@ -20,5 +20,5 @@
 import javax.swing.ImageIcon;
 
-import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.IPrimitive;
 import org.openstreetmap.josm.data.preferences.sources.SourceEntry;
 import org.openstreetmap.josm.data.preferences.sources.SourceType;
@@ -94,6 +94,7 @@
      * we pretend it is. This is useful for generating area styles from the (segmented)
      * outer ways of a multipolygon.
-     */
-    public abstract void apply(MultiCascade mc, OsmPrimitive osm, double scale, boolean pretendWayIsClosed);
+     * @since 13810 (signature)
+     */
+    public abstract void apply(MultiCascade mc, IPrimitive osm, double scale, boolean pretendWayIsClosed);
 
     /**
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/ConditionFactory.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/ConditionFactory.java	(revision 13809)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/ConditionFactory.java	(revision 13810)
@@ -15,4 +15,5 @@
 import java.util.regex.PatternSyntaxException;
 
+import org.openstreetmap.josm.data.osm.IPrimitive;
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
@@ -681,5 +682,5 @@
          * @param e MapCSS environment
          * @return {@code true} if the object has an area style
-         * @see ElemStyles#hasAreaElemStyle(OsmPrimitive, boolean)
+         * @see ElemStyles#hasAreaElemStyle(IPrimitive, boolean)
          */
         static boolean areaStyle(Environment e) { // NO_UCD (unused code)
@@ -749,5 +750,5 @@
          */
         static boolean inDownloadedArea(Environment e) { // NO_UCD (unused code)
-            return IN_DOWNLOADED_AREA.test(e.osm);
+            return e.osm instanceof OsmPrimitive && IN_DOWNLOADED_AREA.test((OsmPrimitive) e.osm);
         }
 
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/ExpressionFactory.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/ExpressionFactory.java	(revision 13809)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/ExpressionFactory.java	(revision 13810)
@@ -460,5 +460,5 @@
                 if (env.osm != null) {
                     // we don't have a matched parent, so just search all referrers
-                    for (OsmPrimitive parent : env.osm.getReferrers()) {
+                    for (IPrimitive parent : env.osm.getReferrers()) {
                         String value = parent.get(key);
                         if (value != null) {
@@ -485,5 +485,5 @@
                     final Collection<String> tags = new TreeSet<>(AlphanumComparator.getInstance());
                     // we don't have a matched parent, so just search all referrers
-                    for (OsmPrimitive parent : env.osm.getReferrers()) {
+                    for (IPrimitive parent : env.osm.getReferrers()) {
                         String value = parent.get(key);
                         if (value != null) {
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java	(revision 13809)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java	(revision 13810)
@@ -30,4 +30,5 @@
 
 import org.openstreetmap.josm.data.Version;
+import org.openstreetmap.josm.data.osm.IPrimitive;
 import org.openstreetmap.josm.data.osm.KeyValueVisitor;
 import org.openstreetmap.josm.data.osm.Node;
@@ -357,6 +358,7 @@
          * @param osm the primitive to match
          * @return An iterator over possible rules in the right order.
-         */
-        public Iterator<MapCSSRule> getRuleCandidates(OsmPrimitive osm) {
+         * @since 13810 (signature)
+         */
+        public Iterator<MapCSSRule> getRuleCandidates(IPrimitive osm) {
             final BitSet ruleCandidates = new BitSet(rules.size());
             ruleCandidates.or(remaining);
@@ -638,5 +640,5 @@
 
     @Override
-    public void apply(MultiCascade mc, OsmPrimitive osm, double scale, boolean pretendWayIsClosed) {
+    public void apply(MultiCascade mc, IPrimitive osm, double scale, boolean pretendWayIsClosed) {
         MapCSSRuleIndex matchingRuleIndex;
         if (osm instanceof Node) {
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(revision 13809)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(revision 13810)
@@ -14,4 +14,9 @@
 import java.util.regex.PatternSyntaxException;
 
+import org.openstreetmap.josm.data.osm.INode;
+import org.openstreetmap.josm.data.osm.IPrimitive;
+import org.openstreetmap.josm.data.osm.IRelation;
+import org.openstreetmap.josm.data.osm.IRelationMember;
+import org.openstreetmap.josm.data.osm.IWay;
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
@@ -19,7 +24,6 @@
 import org.openstreetmap.josm.data.osm.OsmUtils;
 import org.openstreetmap.josm.data.osm.Relation;
-import org.openstreetmap.josm.data.osm.RelationMember;
 import org.openstreetmap.josm.data.osm.Way;
-import org.openstreetmap.josm.data.osm.visitor.OsmPrimitiveVisitor;
+import org.openstreetmap.josm.data.osm.visitor.PrimitiveVisitor;
 import org.openstreetmap.josm.data.osm.visitor.paint.relations.MultipolygonCache;
 import org.openstreetmap.josm.gui.mappaint.Environment;
@@ -145,5 +149,5 @@
          *
          */
-        private class MatchingReferrerFinder implements OsmPrimitiveVisitor {
+        private class MatchingReferrerFinder implements PrimitiveVisitor {
             private final Environment e;
 
@@ -157,10 +161,10 @@
 
             @Override
-            public void visit(Node n) {
+            public void visit(INode n) {
                 // node should never be a referrer
                 throw new AssertionError();
             }
 
-            private <T extends OsmPrimitive> void doVisit(T parent, IntSupplier counter, IntFunction<OsmPrimitive> getter) {
+            private <T extends IPrimitive> void doVisit(T parent, IntSupplier counter, IntFunction<IPrimitive> getter) {
                 // If e.parent is already set to the first matching referrer.
                 // We skip any following referrer injected into the visitor.
@@ -187,15 +191,15 @@
 
             @Override
-            public void visit(Way w) {
+            public void visit(IWay<?> w) {
                 doVisit(w, w::getNodesCount, w::getNode);
             }
 
             @Override
-            public void visit(Relation r) {
+            public void visit(IRelation<?> r) {
                 doVisit(r, r::getMembersCount, i -> r.getMember(i).getMember());
             }
         }
 
-        private abstract static class AbstractFinder implements OsmPrimitiveVisitor {
+        private abstract static class AbstractFinder implements PrimitiveVisitor {
             protected final Environment e;
 
@@ -205,17 +209,17 @@
 
             @Override
-            public void visit(Node n) {
-            }
-
-            @Override
-            public void visit(Way w) {
-            }
-
-            @Override
-            public void visit(Relation r) {
-            }
-
-            public void visit(Collection<? extends OsmPrimitive> primitives) {
-                for (OsmPrimitive p : primitives) {
+            public void visit(INode n) {
+            }
+
+            @Override
+            public void visit(IWay<?> w) {
+            }
+
+            @Override
+            public void visit(IRelation<?> r) {
+            }
+
+            public void visit(Collection<? extends IPrimitive> primitives) {
+                for (IPrimitive p : primitives) {
                     if (e.child != null) {
                         // abort if first match has been found
@@ -227,5 +231,5 @@
             }
 
-            public boolean isPrimitiveUsable(OsmPrimitive p) {
+            public boolean isPrimitiveUsable(IPrimitive p) {
                 return !e.osm.equals(p) && p.isUsable();
             }
@@ -235,5 +239,5 @@
 
             @Override
-            public void visit(Way w) {
+            public void visit(IWay<?> w) {
                 w.visitReferrers(innerVisitor);
             }
@@ -243,9 +247,9 @@
             }
 
-            private final OsmPrimitiveVisitor innerVisitor = new AbstractFinder(e) {
+            private final PrimitiveVisitor innerVisitor = new AbstractFinder(e) {
                 @Override
-                public void visit(Relation r) {
-                    if (left.matches(e.withPrimitive(r))) {
-                        final List<Node> openEnds = MultipolygonCache.getInstance().get(r).getOpenEnds();
+                public void visit(IRelation<?> r) {
+                    if (r instanceof Relation && left.matches(e.withPrimitive(r))) {
+                        final List<Node> openEnds = MultipolygonCache.getInstance().get((Relation) r).getOpenEnds();
                         final int openEndIndex = openEnds.indexOf(e.osm);
                         if (openEndIndex >= 0) {
@@ -265,13 +269,13 @@
             private CrossingFinder(Environment e) {
                 super(e);
-                CheckParameterUtil.ensureThat(e.osm instanceof Way, "Only ways are supported");
+                CheckParameterUtil.ensureThat(e.osm instanceof IWay, "Only ways are supported");
                 layer = OsmUtils.getLayer(e.osm);
             }
 
             @Override
-            public void visit(Way w) {
+            public void visit(IWay<?> w) {
                 if (e.child == null && Objects.equals(layer, OsmUtils.getLayer(w))
                     && left.matches(new Environment(w).withParent(e.osm))
-                    && e.osm instanceof Way && Geometry.PolygonIntersection.CROSSING.equals(
+                    && e.osm instanceof IWay && Geometry.PolygonIntersection.CROSSING.equals(
                             Geometry.polygonIntersection(w.getNodes(), ((Way) e.osm).getNodes()))) {
                     e.child = w;
@@ -283,11 +287,11 @@
             protected ContainsFinder(Environment e) {
                 super(e);
-                CheckParameterUtil.ensureThat(!(e.osm instanceof Node), "Nodes not supported");
-            }
-
-            @Override
-            public void visit(Node n) {
+                CheckParameterUtil.ensureThat(!(e.osm instanceof INode), "Nodes not supported");
+            }
+
+            @Override
+            public void visit(INode n) {
                 if (e.child == null && left.matches(new Environment(n).withParent(e.osm))
-                    && ((e.osm instanceof Way && Geometry.nodeInsidePolygon(n, ((Way) e.osm).getNodes()))
+                    && ((e.osm instanceof IWay && Geometry.nodeInsidePolygon(n, ((Way) e.osm).getNodes()))
                             || (e.osm instanceof Relation && (
                                     (Relation) e.osm).isMultipolygon() && Geometry.isNodeInsideMultiPolygon(n, (Relation) e.osm, null)))) {
@@ -297,7 +301,7 @@
 
             @Override
-            public void visit(Way w) {
+            public void visit(IWay<?> w) {
                 if (e.child == null && left.matches(new Environment(w).withParent(e.osm))
-                    && ((e.osm instanceof Way && Geometry.PolygonIntersection.FIRST_INSIDE_SECOND.equals(
+                    && ((e.osm instanceof IWay && Geometry.PolygonIntersection.FIRST_INSIDE_SECOND.equals(
                             Geometry.polygonIntersection(w.getNodes(), ((Way) e.osm).getNodes())))
                             || (e.osm instanceof Relation && (
@@ -317,5 +321,5 @@
             if (ChildOrParentSelectorType.ELEMENT_OF.equals(type)) {
 
-                if (e.osm instanceof Node || e.osm.getDataSet() == null) {
+                if (e.osm instanceof INode || e.osm.getDataSet() == null) {
                     // nodes cannot contain elements
                     return false;
@@ -326,5 +330,5 @@
                     // if right selector also matches relations and if matched primitive is a way which is part of a multipolygon,
                     // use the multipolygon for further analysis
-                    if (!(e.osm instanceof Way)
+                    if (!(e.osm instanceof IWay)
                             || (right instanceof OptimizedGeneralSelector
                             && !((OptimizedGeneralSelector) right).matchesBase(OsmPrimitiveType.RELATION))) {
@@ -338,5 +342,5 @@
                     containsFinder = new ContainsFinder(new Environment(multipolygon)) {
                         @Override
-                        public boolean isPrimitiveUsable(OsmPrimitive p) {
+                        public boolean isPrimitiveUsable(IPrimitive p) {
                             return super.isPrimitiveUsable(p) && !members.contains(p);
                         }
@@ -362,5 +366,5 @@
                 return e.child != null;
 
-            } else if (ChildOrParentSelectorType.CROSSING.equals(type) && e.osm instanceof Way) {
+            } else if (ChildOrParentSelectorType.CROSSING.equals(type) && e.osm instanceof IWay) {
                 e.parent = e.osm;
                 final CrossingFinder crossingFinder = new CrossingFinder(e);
@@ -371,16 +375,19 @@
                 return e.child != null;
             } else if (ChildOrParentSelectorType.SIBLING.equals(type)) {
-                if (e.osm instanceof Node) {
-                    for (Way w : Utils.filteredCollection(e.osm.getReferrers(true), Way.class)) {
-                        final int i = w.getNodes().indexOf(e.osm);
-                        if (i - 1 >= 0) {
-                            final Node n = w.getNode(i - 1);
-                            final Environment e2 = e.withPrimitive(n).withParent(w).withChild(e.osm);
-                            if (left.matches(e2) && link.matches(e2.withLinkContext())) {
-                                e.child = n;
-                                e.index = i;
-                                e.count = w.getNodesCount();
-                                e.parent = w;
-                                return true;
+                if (e.osm instanceof INode) {
+                    for (IPrimitive ref : e.osm.getReferrers(true)) {
+                        if (ref instanceof IWay) {
+                            IWay<?> w = (IWay<?>) ref;
+                            final int i = w.getNodes().indexOf(e.osm);
+                            if (i - 1 >= 0) {
+                                final INode n = w.getNode(i - 1);
+                                final Environment e2 = e.withPrimitive(n).withParent(w).withChild(e.osm);
+                                if (left.matches(e2) && link.matches(e2.withLinkContext())) {
+                                    e.child = n;
+                                    e.index = i;
+                                    e.count = w.getNodesCount();
+                                    e.parent = w;
+                                    return true;
+                                }
                             }
                         }
@@ -390,5 +397,5 @@
                     && link.conds != null && !link.conds.isEmpty()
                     && link.conds.get(0) instanceof OpenEndPseudoClassCondition) {
-                if (e.osm instanceof Node) {
+                if (e.osm instanceof INode) {
                     e.osm.visitReferrers(new MultipolygonOpenEndFinder(e));
                     return e.parent != null;
@@ -400,8 +407,8 @@
                     return true;
             } else if (ChildOrParentSelectorType.PARENT.equals(type)) {
-                if (e.osm instanceof Way) {
-                    List<Node> wayNodes = ((Way) e.osm).getNodes();
+                if (e.osm instanceof IWay) {
+                    List<? extends INode> wayNodes = ((IWay<?>) e.osm).getNodes();
                     for (int i = 0; i < wayNodes.size(); i++) {
-                        Node n = wayNodes.get(i);
+                        INode n = wayNodes.get(i);
                         if (left.matches(e.withPrimitive(n))
                             && link.matches(e.withChildAndIndexAndLinkContext(n, i, wayNodes.size()))) {
@@ -412,8 +419,8 @@
                         }
                     }
-                } else if (e.osm instanceof Relation) {
-                    List<RelationMember> members = ((Relation) e.osm).getMembers();
+                } else if (e.osm instanceof IRelation) {
+                    List<? extends IRelationMember<?>> members = ((IRelation<?>) e.osm).getMembers();
                     for (int i = 0; i < members.size(); i++) {
-                        OsmPrimitive member = members.get(i).getMember();
+                        IPrimitive member = members.get(i).getMember();
                         if (left.matches(e.withPrimitive(member))
                             && link.matches(e.withChildAndIndexAndLinkContext(member, i, members.size()))) {
@@ -624,11 +631,11 @@
         }
 
-        public boolean matchesBase(OsmPrimitive p) {
+        public boolean matchesBase(IPrimitive p) {
             if (!matchesBase(p.getType())) {
                 return false;
             } else {
-                if (p instanceof Relation) {
+                if (p instanceof IRelation) {
                     if ("area".equals(base)) {
-                        return ((Relation) p).isMultipolygon();
+                        return ((IRelation<?>) p).isMultipolygon();
                     } else if ("canvas".equals(base)) {
                         return p.get("#canvas") != null;
