diff --git a/net/net.c b/net/net.c
index 69456b2..8ae1cd8 100644
--- a/net/net.c
+++ b/net/net.c
@@ -931,55 +931,54 @@ static int net_client_init1(const void *object, bool is_netdev, Error **errp)
         }
     } else {
         const NetLegacy *net = object;
-        const NetClientOptions *opts = net->opts;
         legacy.id = net->id;
         netdev = &legacy;
         /* missing optional values have been initialized to "all bits zero" */
         name = net->has_id ? net->id : net->name;
 
         /* Map the old options to the new flat type */
-        switch (opts->type) {
-        case NET_CLIENT_OPTIONS_KIND_NONE:
+        switch (net->type) {
+        case NET_CLIENT_DRIVER_LEGACY_NONE:
             return 0; /* nothing to do */
-        case NET_CLIENT_OPTIONS_KIND_NIC:
+        case NET_CLIENT_DRIVER_LEGACY_NIC:
             legacy.type = NET_CLIENT_DRIVER_NIC;
-            legacy.nic = opts->nic;
+            legacy.nic = net->nic;
             break;
-        case NET_CLIENT_OPTIONS_KIND_USER:
+        case NET_CLIENT_DRIVER_LEGACY_USER:
             legacy.type = NET_CLIENT_DRIVER_USER;
-            legacy.user = opts->user;
+            legacy.user = net->user;
             break;
-        case NET_CLIENT_OPTIONS_KIND_TAP:
+        case NET_CLIENT_DRIVER_LEGACY_TAP:
             legacy.type = NET_CLIENT_DRIVER_TAP;
-            legacy.tap = opts->tap;
+            legacy.tap = net->tap;
             break;
-        case NET_CLIENT_OPTIONS_KIND_L2TPV3:
+        case NET_CLIENT_DRIVER_LEGACY_L2TPV3:
             legacy.type = NET_CLIENT_DRIVER_L2TPV3;
-            legacy.l2tpv3 = opts->l2tpv3;
+            legacy.l2tpv3 = net->l2tpv3;
             break;
-        case NET_CLIENT_OPTIONS_KIND_SOCKET:
+        case NET_CLIENT_DRIVER_LEGACY_SOCKET:
             legacy.type = NET_CLIENT_DRIVER_SOCKET;
-            legacy.socket = opts->socket;
+            legacy.socket = net->socket;
             break;
-        case NET_CLIENT_OPTIONS_KIND_VDE:
+        case NET_CLIENT_DRIVER_LEGACY_VDE:
             legacy.type = NET_CLIENT_DRIVER_VDE;
-            legacy.vde = opts->vde;
+            legacy.vde = net->vde;
             break;
-        case NET_CLIENT_OPTIONS_KIND_DUMP:
+        case NET_CLIENT_DRIVER_LEGACY_DUMP:
             legacy.type = NET_CLIENT_DRIVER_DUMP;
-            legacy.dump = opts->dump;
+            legacy.dump = net->dump;
             break;
-        case NET_CLIENT_OPTIONS_KIND_BRIDGE:
+        case NET_CLIENT_DRIVER_LEGACY_BRIDGE:
             legacy.type = NET_CLIENT_DRIVER_BRIDGE;
-            legacy.bridge = opts->bridge;
+            legacy.bridge = net->bridge;
             break;
-        case NET_CLIENT_OPTIONS_KIND_NETMAP:
+        case NET_CLIENT_DRIVER_LEGACY_NETMAP:
             legacy.type = NET_CLIENT_DRIVER_NETMAP;
-            legacy.netmap = opts->netmap;
+            legacy.netmap = net->netmap;
             break;
-        case NET_CLIENT_OPTIONS_KIND_VHOST_USER:
+        case NET_CLIENT_DRIVER_LEGACY_VHOST_USER:
             legacy.type = NET_CLIENT_DRIVER_VHOST_USER;
-            legacy.vhost_user = opts->vhost_user;
+            legacy.vhost_user = net->vhost_user;
             break;
         default:
             abort();
@@ -994,7 +993,7 @@ static int net_client_init1(const void *object, bool is_netdev, Error **errp)
 
         /* Do not add to a vlan if it's a nic with a netdev= parameter. */
         if (netdev->type != NET_CLIENT_DRIVER_NIC ||
-            !opts->nic->has_netdev) {
+            !net->nic->has_netdev) {
             peer = net_hub_add_port(net->has_vlan ? net->vlan : 0, NULL);
         }
     }
diff --git a/qapi-schema.json b/qapi-schema.json
index 72827f8..4f9946e 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2531,9 +2531,9 @@
     'vhost-user': 'NetdevVhostUserOptions' } }
 
 ##
-# @NetLegacy
+# @NetLegacyBase
 #
-# Captures the configuration of a network device; legacy.
+# Captures the common configuration of a network device, legacy.
 #
 # @vlan: #optional vlan number
 #
@@ -2541,25 +2541,38 @@
 #
 # @name: #optional identifier for monitor commands, ignored if @id is present
 #
-# @opts: device type specific properties (legacy)
+# @type: specify the driver used for interpreting remaining arguments.
 #
 # Since 1.2
 ##
-{ 'struct': 'NetLegacy',
+{ 'struct': 'NetLegacyBase',
   'data': {
     '*vlan': 'int32',
     '*id':   'str',
     '*name': 'str',
-    'opts':  'NetClientOptions' } }
+    'type':  'NetClientDriverLegacy' } }
 
 ##
-# @NetClientOptions
+# @NetClientDriverLegacy
 #
-# Like Netdev, but for use only by the legacy command line options
+# Available netdev drivers, legacy.
+#
+# Since 2.5
+##
+{'enum': 'NetClientDriverLegacy',
+  'data': [ 'none', 'nic', 'user', 'tap', 'l2tpv3', 'socket', 'vde', 'dump',
+            'bridge', 'netmap', 'vhost-user' ] }
+
+##
+# @NetLegacy
+#
+# Captures the configuration of a network device; legacy.
 #
 # Since 1.2
 ##
-{ 'union': 'NetClientOptions',
+{ 'union': 'NetLegacy',
+  'base': 'NetLegacyBase',
+  'discriminator': 'type',
   'data': {
     'none':     'NetdevNoneOptions',
     'nic':      'NetLegacyNicOptions',
