Index: src/org/openstreetmap/josm/io/session/GpxTracksSessionExporter.java
===================================================================
--- src/org/openstreetmap/josm/io/session/GpxTracksSessionExporter.java	(revision 18392)
+++ src/org/openstreetmap/josm/io/session/GpxTracksSessionExporter.java	(working copy)
@@ -1,6 +1,9 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.io.session;
 
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.io.IOException;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
@@ -8,8 +11,14 @@
 import java.nio.charset.StandardCharsets;
 import java.time.Instant;
 
+import javax.swing.JCheckBox;
+import javax.swing.JPanel;
+
 import org.openstreetmap.josm.gui.layer.GpxLayer;
 import org.openstreetmap.josm.io.GpxWriter;
+import org.openstreetmap.josm.io.session.SessionWriter.ExportSupport;
+import org.openstreetmap.josm.tools.GBC;
+import org.w3c.dom.Element;
 
 /**
  * Session exporter for {@link GpxLayer}.
@@ -18,6 +27,8 @@
 public class GpxTracksSessionExporter extends GenericSessionExporter<GpxLayer> {
 
     private Instant metaTime;
+    private JCheckBox chkMarkers;
+    private boolean hasMarkerLayer;
 
     /**
      * Constructs a new {@code GpxTracksSessionExporter}.
@@ -32,6 +43,38 @@
         if (layer.data == null) {
             throw new IllegalArgumentException("GPX layer without data: " + layer);
         }
+
+        hasMarkerLayer = layer.getLinkedMarkerLayer() != null
+                && layer.getLinkedMarkerLayer().data != null
+                && !layer.getLinkedMarkerLayer().data.isEmpty();
+    }
+
+    @Override
+    public JPanel getExportPanel() {
+        JPanel p = super.getExportPanel();
+        if (hasMarkerLayer) {
+            chkMarkers = new JCheckBox();
+            chkMarkers.setText(tr("include marker layer \"{0}\"", layer.getLinkedMarkerLayer().getName()));
+            chkMarkers.setSelected(true);
+            p.add(chkMarkers, GBC.eol().insets(12, 0, 0, 5));
+        }
+        return p;
+    }
+
+    @Override
+    public Element export(ExportSupport support) throws IOException {
+        Element el = super.export(support);
+        if (hasMarkerLayer && (chkMarkers == null || chkMarkers.isSelected())) {
+            Element markerEl = support.createElement("markerLayer");
+            markerEl.setAttribute("index", Integer.toString(support.getLayerIndexOf(layer.getLinkedMarkerLayer())));
+            markerEl.setAttribute("name", layer.getLinkedMarkerLayer().getName());
+            markerEl.setAttribute("visible", Boolean.toString(layer.getLinkedMarkerLayer().isVisible()));
+            if (layer.getLinkedMarkerLayer().getOpacity() != 1) {
+                markerEl.setAttribute("opacity", Double.toString(layer.getLinkedMarkerLayer().getOpacity()));
+            }
+            el.appendChild(markerEl);
+        }
+        return el;
     }
 
     @Override
Index: src/org/openstreetmap/josm/io/session/GpxTracksSessionImporter.java
===================================================================
--- src/org/openstreetmap/josm/io/session/GpxTracksSessionImporter.java	(revision 18392)
+++ src/org/openstreetmap/josm/io/session/GpxTracksSessionImporter.java	(working copy)
@@ -19,8 +19,11 @@
 import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.openstreetmap.josm.io.IllegalDataException;
+import org.openstreetmap.josm.tools.Logging;
 import org.openstreetmap.josm.tools.Utils;
 import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
 
 /**
  * Session exporter for {@link GpxLayer}.
@@ -57,6 +60,16 @@
                 if (importData.getGpxLayer() != null && importData.getGpxLayer().data != null) {
                     importData.getGpxLayer().data.fromSession = true;
                 }
+                NodeList markerNodes = elem.getElementsByTagName("markerLayer");
+                if (markerNodes.getLength() > 0 && markerNodes.item(0).getNodeType() == Node.ELEMENT_NODE) {
+                    Element markerEl = (Element) markerNodes.item(0);
+                    try {
+                        int index = Integer.parseInt(markerEl.getAttribute("index"));
+                        support.addSubLayer(index, importData.getMarkerLayer(), markerEl);
+                    } catch (NumberFormatException ex) {
+                        Logging.warn(ex);
+                    }
+                }
 
                 support.addPostLayersTask(importData.getPostLayerTask());
                 return getLayer(importData);
Index: src/org/openstreetmap/josm/io/session/MarkerSessionExporter.java
===================================================================
--- src/org/openstreetmap/josm/io/session/MarkerSessionExporter.java	(revision 18392)
+++ src/org/openstreetmap/josm/io/session/MarkerSessionExporter.java	(working copy)
@@ -34,6 +34,7 @@
 public class MarkerSessionExporter extends AbstractSessionExporter<MarkerLayer> {
 
     private Instant metaTime;
+    private boolean canExport = true;
 
     /**
      * Constructs a new {@code MarkerSessionExporter}.
@@ -53,8 +54,12 @@
 
     @Override
     public Component getExportPanel() {
+        export.setSelected(true); //true even when not shown to the user as the index should be reserved for the corresponding GPX layer
+        if (layer.fromLayer != null && layer.fromLayer.getData() != null) {
+            canExport = false;
+            return null;
+        }
         final JPanel p = new JPanel(new GridBagLayout());
-        export.setSelected(true);
         final JLabel lbl = new JLabel(layer.getName(), layer.getIcon(), SwingConstants.LEADING);
         lbl.setToolTipText(layer.getToolTipText());
         lbl.setLabelFor(export);
@@ -66,11 +71,13 @@
 
     @Override
     public boolean requiresZip() {
-        return true;
+        return canExport;
     }
 
     @Override
     public Element export(ExportSupport support) throws IOException {
+        if (!canExport) return null;
+
         Element layerEl = support.createElement("layer");
         layerEl.setAttribute("type", "markers");
         layerEl.setAttribute("version", "0.1");
Index: src/org/openstreetmap/josm/io/session/MarkerSessionImporter.java
===================================================================
--- src/org/openstreetmap/josm/io/session/MarkerSessionImporter.java	(revision 18392)
+++ src/org/openstreetmap/josm/io/session/MarkerSessionImporter.java	(working copy)
@@ -48,6 +48,7 @@
 
                 support.addPostLayersTask(importData.getPostLayerTask());
 
+                importData.getGpxLayer().destroy();
                 return importData.getMarkerLayer();
             }
         } catch (XPathExpressionException e) {
Index: src/org/openstreetmap/josm/io/session/SessionReader.java
===================================================================
--- src/org/openstreetmap/josm/io/session/SessionReader.java	(revision 18392)
+++ src/org/openstreetmap/josm/io/session/SessionReader.java	(working copy)
@@ -14,6 +14,7 @@
 import java.net.URISyntaxException;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
+import java.util.AbstractMap.SimpleEntry;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -250,6 +251,7 @@
         private final String layerName;
         private final int layerIndex;
         private final List<LayerDependency> layerDependencies;
+        private Map<Integer, Entry<Layer, Element>> subLayers;
 
         /**
          * Path of the file inside the zip archive.
@@ -279,6 +281,31 @@
         }
 
         /**
+         * Add sub layers
+         * @param idx index
+         * @param layer sub layer
+         * @param el The XML element of the sub layer.
+         *           Should contain "index" and "name" attributes.
+         *           Can contain "opacity" and "visible" attributes
+         * @since xxx
+         */
+        public void addSubLayer(int idx, Layer layer, Element el) {
+            if (subLayers == null) {
+                subLayers = new HashMap<>();
+            }
+            subLayers.put(idx, new SimpleEntry<>(layer, el));
+        }
+
+        /**
+         * Returns the sub layers
+         * @return the sub layers. Can be null.
+         * @since xxx
+         */
+        public Map<Integer, Entry<Layer, Element>> getSubLayers() {
+            return subLayers;
+        }
+
+        /**
          * Return an InputStream for a URI from a .jos/.joz file.
          *
          * The following forms are supported:
@@ -506,7 +533,6 @@
         List<Integer> sorted = Utils.topologicalSort(deps);
         final Map<Integer, Layer> layersMap = new TreeMap<>(Collections.reverseOrder());
         final Map<Integer, SessionLayerImporter> importers = new HashMap<>();
-        final Map<Integer, String> names = new HashMap<>();
 
         progressMonitor.setTicksCount(sorted.size());
         LAYER: for (int idx: sorted) {
@@ -519,7 +545,6 @@
                 return;
             }
             String name = e.getAttribute("name");
-            names.put(idx, name);
             if (!e.hasAttribute("type")) {
                 error(tr("missing mandatory attribute ''type'' for element ''layer''"));
                 return;
@@ -595,30 +620,49 @@
                 }
 
                 layersMap.put(idx, layer);
+                setLayerAttributes(layer, e);
+
+                if (support.getSubLayers() != null) {
+                    support.getSubLayers().forEach((Integer markerIndex, Entry<Layer, Element> entry) -> {
+                        Layer subLayer = entry.getKey();
+                        Element subElement = entry.getValue();
+
+                        layersMap.put(markerIndex, subLayer);
+                        setLayerAttributes(subLayer, subElement);
+                    });
+                }
+
             }
             progressMonitor.worked(1);
         }
 
+
         layers = new ArrayList<>();
         for (Entry<Integer, Layer> entry : layersMap.entrySet()) {
             Layer layer = entry.getValue();
-            if (layer == null) {
-                continue;
-            }
-            Element el = elems.get(entry.getKey());
-            if (el.hasAttribute("visible")) {
-                layer.setVisible(Boolean.parseBoolean(el.getAttribute("visible")));
+            if (layer != null) {
+                layers.add(layer);
             }
-            if (el.hasAttribute("opacity")) {
-                try {
-                    double opacity = Double.parseDouble(el.getAttribute("opacity"));
-                    layer.setOpacity(opacity);
-                } catch (NumberFormatException ex) {
-                    Logging.warn(ex);
-                }
+        }
+    }
+
+    private static void setLayerAttributes(Layer layer, Element e) {
+        if (layer == null)
+            return;
+
+        if (e.hasAttribute("name")) {
+            layer.setName(e.getAttribute("name"));
+        }
+        if (e.hasAttribute("visible")) {
+            layer.setVisible(Boolean.parseBoolean(e.getAttribute("visible")));
+        }
+        if (e.hasAttribute("opacity")) {
+            try {
+                double opacity = Double.parseDouble(e.getAttribute("opacity"));
+                layer.setOpacity(opacity);
+            } catch (NumberFormatException ex) {
+                Logging.warn(ex);
             }
-            layer.setName(names.get(entry.getKey()));
-            layers.add(layer);
         }
     }
 
Index: src/org/openstreetmap/josm/io/session/SessionWriter.java
===================================================================
--- src/org/openstreetmap/josm/io/session/SessionWriter.java	(revision 18392)
+++ src/org/openstreetmap/josm/io/session/SessionWriter.java	(working copy)
@@ -174,6 +174,16 @@
         }
 
         /**
+         * Get the index of the specified layer
+         * @param layer the layer
+         * @return the index of the specified layer
+         * @since xxx
+         */
+        public int getLayerIndexOf(Layer layer) {
+            return layers.indexOf(layer) + 1;
+        }
+
+        /**
          * Create a file inside the zip archive.
          *
          * @param zipPath the path inside the zip archive, e.g. "layers/03/data.xml"
@@ -234,6 +244,7 @@
             SessionLayerExporter exporter = exporters.get(layer);
             ExportSupport support = new ExportSupport(doc, index+1);
             Element el = exporter.export(support);
+            if (el == null) continue;
             el.setAttribute("index", Integer.toString(index+1));
             el.setAttribute("name", layer.getName());
             el.setAttribute("visible", Boolean.toString(layer.isVisible()));
Index: test/data/sessions/gpx_markers_combined.jos
===================================================================
--- test/data/sessions/gpx_markers_combined.jos	(nonexistent)
+++ test/data/sessions/gpx_markers_combined.jos	(working copy)
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<josm-session version="0.1">
+    <viewport>
+        <center lat="0.0" lon="0.0"/>
+        <scale meter-per-pixel="10.000000"/>
+    </viewport>
+    <projection>
+        <projection-choice>
+            <id>core:mercator</id>
+            <parameters/>
+        </projection-choice>
+        <code>EPSG:3857</code>
+    </projection>
+    <layers>
+        <layer index="1" name="GPX layer name" type="tracks" version="0.1" visible="true">
+            <file>layers/01/data.gpx</file>
+            <markerLayer index="2" name="Marker layer name" opacity="0.5" visible="true"/>
+        </layer>
+    </layers>
+</josm-session>
Index: test/unit/org/openstreetmap/josm/io/session/SessionWriterTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/io/session/SessionWriterTest.java	(revision 18392)
+++ test/unit/org/openstreetmap/josm/io/session/SessionWriterTest.java	(working copy)
@@ -50,7 +50,7 @@
 /**
  * Unit tests for Session writing.
  */
-class SessionWriterTest {
+public class SessionWriterTest {
 
     protected static final class OsmHeadlessJosExporter extends OsmDataSessionExporter {
         public OsmHeadlessJosExporter(OsmDataLayer layer) {
@@ -122,6 +122,7 @@
         }
         for (final Layer l : layers) {
             SessionLayerExporter s = SessionWriter.getSessionLayerExporter(l);
+            s.getExportPanel();
             exporters.put(l, s);
             if (s instanceof GpxTracksSessionExporter) {
                 ((GpxTracksSessionExporter) s).setMetaTime(Instant.parse("2021-10-16T18:27:12.351Z"));
@@ -153,13 +154,20 @@
         }
     }
 
-    private OsmDataLayer createOsmLayer() {
+    /**
+     * Returns OSM layer
+     * @return OSM layer
+     */
+    public static OsmDataLayer createOsmLayer() {
         OsmDataLayer layer = new OsmDataLayer(new DataSet(), "OSM layer name", null);
         layer.setAssociatedFile(new File("data.osm"));
         return layer;
     }
 
-    private GpxLayer createGpxLayer() {
+    /**Returns GPX layer
+     * @return GPX layer
+     */
+    public static GpxLayer createGpxLayer() {
         GpxData data = new GpxData();
         WayPoint wp = new WayPoint(new LatLon(42.72665, -0.00747));
         wp.setInstant(Instant.parse("2021-01-01T10:15:30.00Z"));
@@ -170,21 +178,35 @@
         return layer;
     }
 
-    private MarkerLayer createMarkerLayer(GpxLayer gpx) {
+    /**
+     * Returns MarkerLayer
+     * @param gpx linked GPX layer
+     * @return MarkerLayer
+     */
+    public static MarkerLayer createMarkerLayer(GpxLayer gpx) {
         MarkerLayer layer = new MarkerLayer(gpx.data, "Marker layer name", gpx.getAssociatedFile(), gpx);
         layer.setOpacity(0.5);
         layer.setColor(new Color(0x12345678, true));
+        gpx.setLinkedMarkerLayer(layer);
         return layer;
     }
 
-    private ImageryLayer createImageryLayer() {
+    /**
+     * Returns ImageryLayer
+     * @return ImageryLayer
+     */
+    public static ImageryLayer createImageryLayer() {
         TMSLayer layer = new TMSLayer(new ImageryInfo("the name", "http://www.url.com/"));
         layer.getDisplaySettings().setOffsetBookmark(
                 new OffsetBookmark(ProjectionRegistry.getProjection().toCode(), layer.getInfo().getId(), layer.getInfo().getName(), "", 12, 34));
         return layer;
     }
 
-    private NoteLayer createNoteLayer() {
+    /**
+     * Returns NoteLayer
+     * @return NoteLayer
+     */
+    public static NoteLayer createNoteLayer() {
         return new NoteLayer(Arrays.asList(new Note(LatLon.ZERO)), "layer name");
     }
 
@@ -249,9 +271,10 @@
     @Test
     void testWriteGpxAndMarkerJoz() throws IOException {
         GpxLayer gpx = createGpxLayer();
-        Map<String, byte[]> bytes = testWrite(Arrays.asList(gpx, createMarkerLayer(gpx)), true);
+        MarkerLayer markers = createMarkerLayer(gpx);
+        Map<String, byte[]> bytes = testWrite(Arrays.asList(gpx, markers), true);
 
-        Path path = Paths.get(TestUtils.getTestDataRoot() + "/sessions/gpx_markers.jos");
+        Path path = Paths.get(TestUtils.getTestDataRoot() + "/sessions/gpx_markers_combined.jos");
         String expected = new String(Files.readAllBytes(path), StandardCharsets.UTF_8).replace("\r", "");
         String actual = new String(bytes.get("session.jos"), StandardCharsets.UTF_8).replace("\r", "");
         assertEquals(expected, actual);
@@ -261,10 +284,27 @@
         actual = new String(bytes.get("layers/01/data.gpx"), StandardCharsets.UTF_8).replace("\r", "");
         assertEquals(expected, actual);
 
+        //Test writing when the marker layer has no corresponding GPX layer:
+        gpx.setLinkedMarkerLayer(null);
+        markers.fromLayer = null;
+        markers.data.transferLayerPrefs(gpx.data.getLayerPrefs());
+        bytes = testWrite(Arrays.asList(gpx, markers), true);
+
+        path = Paths.get(TestUtils.getTestDataRoot() + "/sessions/gpx_markers.jos");
+        expected = new String(Files.readAllBytes(path), StandardCharsets.UTF_8).replace("\r", "");
+        actual = new String(bytes.get("session.jos"), StandardCharsets.UTF_8).replace("\r", "");
+        assertEquals(expected, actual);
+
+        path = Paths.get(TestUtils.getTestDataRoot() + "/sessions/data_export.gpx");
+        expected = new String(Files.readAllBytes(path), StandardCharsets.UTF_8).replace("\r", "");
+        actual = new String(bytes.get("layers/01/data.gpx"), StandardCharsets.UTF_8).replace("\r", "");
+        assertEquals(expected, actual);
+
         path = Paths.get(TestUtils.getTestDataRoot() + "/sessions/markers.gpx");
         expected = new String(Files.readAllBytes(path), StandardCharsets.UTF_8).replace("\r", "");
         actual = new String(bytes.get("layers/02/data.gpx"), StandardCharsets.UTF_8).replace("\r", "");
         assertEquals(expected, actual);
+
     }
 
     /**
