Index: src/org/openstreetmap/josm/data/gpx/GpxData.java
===================================================================
--- src/org/openstreetmap/josm/data/gpx/GpxData.java	(revision 16107)
+++ src/org/openstreetmap/josm/data/gpx/GpxData.java	(working copy)
@@ -22,10 +22,10 @@
 import java.util.stream.Stream;
 
 import org.openstreetmap.josm.data.Bounds;
-import org.openstreetmap.josm.data.Data;
 import org.openstreetmap.josm.data.DataSource;
 import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.gpx.IGpxTrack.GpxTrackChangeListener;
+import org.openstreetmap.josm.data.osm.OsmData;
 import org.openstreetmap.josm.data.projection.ProjectionRegistry;
 import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.gui.layer.GpxLayer;
@@ -39,7 +39,7 @@
  *
  * @author Raphael Mack &lt;ramack@raphael-mack.de&gt;
  */
-public class GpxData extends WithAttributes implements Data {
+public class GpxData extends WithAttributes implements OsmData<GeoImagePrimitive, GpxImageEntry, GpxImageTrack, GpxImageRelation> {
 
     /**
      * Constructs a new GpxData.
Index: src/org/openstreetmap/josm/data/gpx/GpxImageEntry.java
===================================================================
--- src/org/openstreetmap/josm/data/gpx/GpxImageEntry.java	(revision 16107)
+++ src/org/openstreetmap/josm/data/gpx/GpxImageEntry.java	(working copy)
@@ -9,7 +9,15 @@
 import java.util.function.Consumer;
 
 import org.openstreetmap.josm.data.coor.CachedLatLon;
+import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.BBox;
+import org.openstreetmap.josm.data.osm.INode;
+import org.openstreetmap.josm.data.osm.IPrimitive;
+import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
+import org.openstreetmap.josm.data.osm.UniqueIdGenerator;
+import org.openstreetmap.josm.data.osm.visitor.PrimitiveVisitor;
+import org.openstreetmap.josm.data.projection.ProjectionRegistry;
 import org.openstreetmap.josm.tools.ExifReader;
 import org.openstreetmap.josm.tools.JosmRuntimeException;
 import org.openstreetmap.josm.tools.Logging;
@@ -28,7 +36,8 @@
  * Stores info about each image
  * @since 14205 (extracted from gui.layer.geoimage.ImageEntry)
  */
-public class GpxImageEntry implements Comparable<GpxImageEntry> {
+public class GpxImageEntry extends GeoImagePrimitive implements INode {
+    private static final UniqueIdGenerator idGenerator = new UniqueIdGenerator();
     private File file;
     private Integer exifOrientation;
     private LatLon exifCoor;
@@ -414,15 +423,19 @@
     }
 
     @Override
-    public int compareTo(GpxImageEntry image) {
-        if (exifTime != null && image.exifTime != null)
-            return exifTime.compareTo(image.exifTime);
-        else if (exifTime == null && image.exifTime == null)
-            return 0;
-        else if (exifTime == null)
-            return -1;
-        else
-            return 1;
+    public int compareTo(IPrimitive iPrimitive) {
+        if (iPrimitive instanceof GpxImageEntry) {
+            GpxImageEntry image = (GpxImageEntry) iPrimitive;
+            if (exifTime != null && image.exifTime != null)
+                return exifTime.compareTo(image.exifTime);
+            else if (exifTime == null && image.exifTime == null)
+                return 0;
+            else if (exifTime == null)
+                return -1;
+            else
+                return 1;
+        }
+        return hashCode() - iPrimitive.hashCode();
     }
 
     @Override
@@ -513,6 +526,7 @@
      * If it has been tagged i.e. matched to a gpx track or retrieved lat/lon from exif
      * @return {@code true} if it has been tagged
      */
+    @Override
     public boolean isTagged() {
         return pos != null;
     }
@@ -654,4 +668,66 @@
             setter.accept(value);
         }
     }
+
+    @Override
+    public void accept(PrimitiveVisitor visitor) {
+        visitor.visit(this);
+    }
+
+    @Override
+    public void visitReferrers(PrimitiveVisitor visitor) {
+        this.getReferrers().forEach(i -> i.accept(visitor));
+    }
+
+    @Override
+    public BBox getBBox() {
+        return new BBox(getCoor());
+    }
+
+    @Override
+    public List<? extends IPrimitive> getReferrers(boolean allowWithoutDataset) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public OsmPrimitiveType getType() {
+        return OsmPrimitiveType.NODE;
+    }
+
+    @Override
+    public double lon() {
+        return getCoor().lon();
+    }
+
+    @Override
+    public double lat() {
+        return getCoor().lat();
+    }
+
+    @Override
+    public LatLon getCoor() {
+        return pos;
+    }
+
+    @Override
+    public void setCoor(LatLon coor) {
+        pos = new CachedLatLon(coor);
+    }
+
+    @Override
+    public void setEastNorth(EastNorth eastNorth) {
+        pos = new CachedLatLon(ProjectionRegistry.getProjection().eastNorth2latlon(eastNorth));
+    }
+
+    @Override
+    public boolean isReferredByWays(int n) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public UniqueIdGenerator getIdGenerator() {
+        return idGenerator;
+    }
 }
Index: src/org/openstreetmap/josm/data/gpx/GpxImageRelation.java
===================================================================
--- src/org/openstreetmap/josm/data/gpx/GpxImageRelation.java	(nonexistent)
+++ src/org/openstreetmap/josm/data/gpx/GpxImageRelation.java	(working copy)
@@ -0,0 +1,95 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.gpx;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.openstreetmap.josm.data.osm.BBox;
+import org.openstreetmap.josm.data.osm.IPrimitive;
+import org.openstreetmap.josm.data.osm.IRelation;
+import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
+import org.openstreetmap.josm.data.osm.RelationMember;
+import org.openstreetmap.josm.data.osm.UniqueIdGenerator;
+import org.openstreetmap.josm.data.osm.visitor.PrimitiveVisitor;
+
+public class GpxImageRelation extends GeoImagePrimitive implements IRelation<RelationMember> {
+    List<RelationMember> members = new ArrayList<>();
+    private static final UniqueIdGenerator idGenerator = new UniqueIdGenerator();
+    @Override
+    public void accept(PrimitiveVisitor visitor) {
+        visitor.visit(this);
+    }
+
+    @Override
+    public BBox getBBox() {
+        BBox returnBBox = new BBox();
+        getReferrers().forEach(p -> returnBBox.add(p.getBBox()));
+        return null;
+    }
+
+    @Override
+    public List<? extends IPrimitive> getReferrers(boolean allowWithoutDataset) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public OsmPrimitiveType getType() {
+        return OsmPrimitiveType.RELATION;
+    }
+
+    @Override
+    public int compareTo(IPrimitive o) {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    @Override
+    public UniqueIdGenerator getIdGenerator() {
+        return idGenerator;
+    }
+
+    @Override
+    protected void keysChangedImpl(Map<String, String> originalKeys) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public int getMembersCount() {
+        return members.size();
+    }
+
+    @Override
+    public RelationMember getMember(int index) {
+        return members.get(index);
+    }
+
+    @Override
+    public List<RelationMember> getMembers() {
+        return new ArrayList<>(members);
+    }
+
+    @Override
+    public void setMembers(List<RelationMember> members) {
+        this.members.clear();
+        this.members.addAll(members);
+    }
+
+    @Override
+    public long getMemberId(int idx) {
+        return members.get(idx).getUniqueId();
+    }
+
+    @Override
+    public String getRole(int idx) {
+        return members.get(idx).getRole();
+    }
+
+    @Override
+    public OsmPrimitiveType getMemberType(int idx) {
+        return members.get(idx).getType();
+    }
+
+}
Index: src/org/openstreetmap/josm/data/gpx/GpxImageTrack.java
===================================================================
--- src/org/openstreetmap/josm/data/gpx/GpxImageTrack.java	(nonexistent)
+++ src/org/openstreetmap/josm/data/gpx/GpxImageTrack.java	(working copy)
@@ -0,0 +1,169 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.gpx;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.osm.BBox;
+import org.openstreetmap.josm.data.osm.INode;
+import org.openstreetmap.josm.data.osm.IPrimitive;
+import org.openstreetmap.josm.data.osm.IWay;
+import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
+import org.openstreetmap.josm.data.osm.UniqueIdGenerator;
+import org.openstreetmap.josm.data.osm.visitor.PrimitiveVisitor;
+
+/**
+ * @author Taylor Smock
+ * @since xxx
+ */
+public class GpxImageTrack extends GeoImagePrimitive implements IWay<GpxImageEntry>, IGpxTrack {
+    List<GpxImageEntry> images = new ArrayList<>();
+    private static final UniqueIdGenerator idGenerator = new UniqueIdGenerator();
+    @Override
+    public void accept(PrimitiveVisitor visitor) {
+        visitor.visit(this);
+    }
+
+    @Override
+    public void visitReferrers(PrimitiveVisitor visitor) {
+        this.getReferrers().forEach(p -> p.accept(visitor));
+    }
+
+    @Override
+    public BBox getBBox() {
+        BBox returnBBox = new BBox();
+        getNodes().forEach(n -> returnBBox.add(n.getBBox()));
+        return returnBBox;
+    }
+
+    @Override
+    public List<? extends IPrimitive> getReferrers(boolean allowWithoutDataset) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public OsmPrimitiveType getType() {
+        return isClosed() ? OsmPrimitiveType.CLOSEDWAY : OsmPrimitiveType.WAY;
+    }
+
+    @Override
+    public String getString(String key) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public <T> Collection<T> getCollection(String key) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public void put(String key, Object value) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public Map<String, Object> getAttributes() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public GpxExtensionCollection getExtensions() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public Collection<IGpxTrackSegment> getSegments() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public Bounds getBounds() {
+        Bounds bounds = new Bounds(firstNode().getCoor(), lastNode().getCoor());
+        images.forEach(i -> bounds.extend(i.getCoor()));
+        return bounds;
+    }
+
+    @Override
+    public double length() {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    @Override
+    public int getNodesCount() {
+        return images.size();
+    }
+
+    @Override
+    public GpxImageEntry getNode(int index) {
+        return images.get(index);
+    }
+
+    @Override
+    public List<GpxImageEntry> getNodes() {
+        return new ArrayList<>(images);
+    }
+
+    @Override
+    public List<Long> getNodeIds() {
+        return images.stream().map(IPrimitive::getUniqueId).collect(Collectors.toList());
+    }
+
+    @Override
+    public long getNodeId(int idx) {
+        return images.get(idx).getUniqueId();
+    }
+
+    @Override
+    public void setNodes(List<GpxImageEntry> nodes) {
+        images.clear();
+        images.addAll(nodes);
+    }
+
+    @Override
+    public boolean isClosed() {
+        return firstNode().equals(lastNode());
+    }
+
+    @Override
+    public GpxImageEntry firstNode() {
+        return images.get(0);
+    }
+
+    @Override
+    public GpxImageEntry lastNode() {
+        return images.get(images.size() - 1);
+    }
+
+    @Override
+    public boolean isFirstLastNode(INode n) {
+        return firstNode().equals(n) || lastNode().equals(n);
+    }
+
+    @Override
+    public boolean isInnerNode(INode n) {
+        return !isFirstLastNode(n);
+    }
+
+    @Override
+    public UniqueIdGenerator getIdGenerator() {
+        return idGenerator;
+    }
+
+    @Override
+    protected void keysChangedImpl(Map<String, String> originalKeys) {
+        // TODO Auto-generated method stub
+
+    }
+}
