diff --git a/libbpf-cargo/src/gen/btf.rs b/libbpf-cargo/src/gen/btf.rs
index a79c6903..f5eea6c9 100644
--- a/libbpf-cargo/src/gen/btf.rs
+++ b/libbpf-cargo/src/gen/btf.rs
@@ -10,6 +10,7 @@ use std::fmt::Write;
 use std::mem::size_of;
 use std::num::NonZeroUsize;
 use std::ops::Deref;
+use std::rc::Rc;
 
 use anyhow::anyhow;
 use anyhow::bail;
@@ -367,6 +368,20 @@ fn escape_reserved_keyword(identifier: Cow<'_, str>) -> Cow<'_, str> {
     }
 }
 
+#[derive(Debug, Clone)]
+struct BtfDependency {
+    /// Name of the dependency parent
+    parent_name: Option<String>,
+
+    /// Dependency id relative to the parent's `child_counter`
+    dep_id: i32,
+
+    /// The `child_counter` for the dependency if it is intended to be
+    /// a parent itself.
+    /// For an anonymous unit this should be a pointer to the parent's `child_counter`
+    child_counter: Rc<RefCell<i32>>,
+}
+
 #[derive(Debug, Default)]
 pub(crate) struct TypeMap {
     /// A mapping from type to number, allowing us to assign numbers to
@@ -377,15 +392,75 @@ pub(crate) struct TypeMap {
     /// Mapping from type name to the number of times we have seen this
     /// name already.
     names_count: RefCell<HashMap<String, u8>>,
+
+    /// Mapping from type to it's parent. Used in anonymous members naming
+    dependency_tree: RefCell<HashMap<TypeId, BtfDependency>>,
 }
 
 impl TypeMap {
+    fn register_parent<'s>(&self, ty: &BtfType<'s>, parent: &BtfType<'s>) {
+        let mut deps = self.dependency_tree.borrow_mut();
+        if deps.get(&ty.type_id()).is_some() {
+            return;
+        }
+
+        let pdep = deps.entry(parent.type_id()).or_insert(BtfDependency {
+            parent_name: None,
+            dep_id: 0,
+            child_counter: Rc::new(RefCell::new(0)),
+        });
+
+        let mut dep = pdep.clone();
+
+        // If parent is named, derive it.
+        // Otherwise derive parent's parent
+        if let Some(n) = parent.name() {
+            dep.parent_name = Some(n.to_string_lossy().to_string());
+        }
+
+        // If the current unit is named, self-assign the child_counter.
+        // Otherwise derive a parent's one
+        if ty.name().is_some() {
+            dep.child_counter = Rc::new(RefCell::new(0));
+        }
+
+        // Increment parent's `child_counter` and assign the new value to dep_id
+        let parent_counter = Rc::clone(&pdep.child_counter);
+        *parent_counter.borrow_mut() += 1;
+        dep.dep_id = *parent_counter.borrow();
+
+        deps.insert(ty.type_id(), dep);
+    }
+
+    fn lookup_parent<'s>(&self, ty: &BtfType<'s>) -> Option<BtfDependency> {
+        self.dependency_tree.borrow().get(&ty.type_id()).cloned()
+    }
+
     pub fn type_name_or_anon<'s>(&self, ty: &BtfType<'s>) -> Cow<'s, str> {
         match ty.name() {
             None => {
                 let mut anon_table = self.types.borrow_mut();
                 let len = anon_table.len() + 1; // use 1 index anon ids for backwards compat
-                let anon_id = anon_table.entry(ty.type_id()).or_insert(len);
+
+                let anon_id = match anon_table.entry(ty.type_id()) {
+                    Entry::Occupied(anon_id) => {
+                        let anon_id = anon_id.get();
+                        *anon_id
+                    }
+                    Entry::Vacant(anon_id) => {
+                        if let Some(dep) = self.lookup_parent(ty) {
+                            if let Some(name) = dep.parent_name {
+                                if !name.is_empty() {
+                                    return format!("{ANON_PREFIX}{}_{}", name, dep.dep_id).into();
+                                }
+                            }
+                        }
+
+                        let anon_id = anon_id.insert(len);
+                        *anon_id
+                    }
+                };
+
                 format!("{ANON_PREFIX}{anon_id}").into()
             }
             Some(n) => match self.names.borrow_mut().entry(ty.type_id()) {
@@ -726,6 +801,7 @@ impl<'s> GenBtf<'s> {
             }
 
             if let Some(next_ty_id) = next_type(field_ty)? {
+                self.type_map.register_parent(&next_ty_id, &t);
                 dependent_types.push(next_ty_id);
             }
             let field_name = if let Some(name) = member.name {
diff --git a/libbpf-cargo/src/test.rs b/libbpf-cargo/src/test.rs
index cc249314..f678d4c2 100644
--- a/libbpf-cargo/src/test.rs
+++ b/libbpf-cargo/src/test.rs
@@ -2514,24 +2514,24 @@ struct Foo foo;
 #[repr(C)]
 pub struct Foo {
     pub x: i32,
-    pub bar: __anon_1,
+    pub bar: __anon_Foo_1,
     pub __pad_36: [u8; 4],
-    pub baz: __anon_2,
+    pub baz: __anon_Foo_2,
     pub w: i32,
     pub __pad_52: [u8; 4],
 }
 #[derive(Copy, Clone)]
 #[repr(C)]
-pub union __anon_1 {
+pub union __anon_Foo_1 {
     pub y: [u8; 10],
     pub z: [u16; 16],
 }
-impl std::fmt::Debug for __anon_1 {
+impl std::fmt::Debug for __anon_Foo_1 {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         write!(f, "(???)")
     }
 }
-impl Default for __anon_1 {
+impl Default for __anon_Foo_1 {
     fn default() -> Self {
         Self {
             y: [u8::default(); 10],
@@ -2540,16 +2540,16 @@ impl Default for __anon_1 {
 }
 #[derive(Copy, Clone)]
 #[repr(C)]
-pub union __anon_2 {
+pub union __anon_Foo_2 {
     pub w: u32,
     pub u: *mut u64,
 }
-impl std::fmt::Debug for __anon_2 {
+impl std::fmt::Debug for __anon_Foo_2 {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         write!(f, "(???)")
     }
 }
-impl Default for __anon_2 {
+impl Default for __anon_Foo_2 {
     fn default() -> Self {
         Self {
             w: u32::default(),
@@ -2594,25 +2594,25 @@ struct Foo foo;
 #[repr(C)]
 pub struct Foo {
     pub x: i32,
-    pub bar: __anon_1,
-    pub baz: __anon_2,
+    pub bar: __anon_Foo_1,
+    pub baz: __anon_Foo_2,
     pub w: i32,
     pub __pad_68: [u8; 4],
 }
 #[derive(Debug, Default, Copy, Clone)]
 #[repr(C)]
-pub struct __anon_1 {
+pub struct __anon_Foo_1 {
     pub y: [u8; 10],
     pub z: [u16; 16],
 }
 #[derive(Debug, Copy, Clone)]
 #[repr(C)]
-pub struct __anon_2 {
+pub struct __anon_Foo_2 {
     pub w: u32,
     pub __pad_4: [u8; 4],
     pub u: *mut u64,
 }
-impl Default for __anon_2 {
+impl Default for __anon_Foo_2 {
     fn default() -> Self {
         Self {
             w: u32::default(),
@@ -2667,31 +2667,31 @@ struct Foo foo;
 #[repr(C)]
 pub struct Foo {
     pub x: i32,
-    pub bar: __anon_1,
-    pub zerg: __anon_2,
-    pub baz: __anon_3,
+    pub bar: __anon_Foo_1,
+    pub zerg: __anon_Foo_2,
+    pub baz: __anon_Foo_3,
     pub w: i32,
     pub __pad_76: [u8; 4],
-    pub flarg: __anon_4,
+    pub flarg: __anon_Foo_4,
 }
 #[derive(Debug, Default, Copy, Clone)]
 #[repr(C)]
-pub struct __anon_1 {
+pub struct __anon_Foo_1 {
     pub y: [u8; 10],
     pub z: [u16; 16],
 }
 #[derive(Copy, Clone)]
 #[repr(C)]
-pub union __anon_2 {
+pub union __anon_Foo_2 {
     pub a: *mut i8,
     pub b: i32,
 }
-impl std::fmt::Debug for __anon_2 {
+impl std::fmt::Debug for __anon_Foo_2 {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         write!(f, "(???)")
     }
 }
-impl Default for __anon_2 {
+impl Default for __anon_Foo_2 {
     fn default() -> Self {
         Self {
             a: std::ptr::null_mut(),
@@ -2700,12 +2700,12 @@ impl Default for __anon_2 {
 }
 #[derive(Debug, Copy, Clone)]
 #[repr(C)]
-pub struct __anon_3 {
+pub struct __anon_Foo_3 {
     pub w: u32,
     pub __pad_4: [u8; 4],
     pub u: *mut u64,
 }
-impl Default for __anon_3 {
+impl Default for __anon_Foo_3 {
     fn default() -> Self {
         Self {
             w: u32::default(),
@@ -2716,16 +2716,16 @@ impl Default for __anon_3 {
 }
 #[derive(Copy, Clone)]
 #[repr(C)]
-pub union __anon_4 {
+pub union __anon_Foo_4 {
     pub c: u8,
     pub d: [u64; 5],
 }
-impl std::fmt::Debug for __anon_4 {
+impl std::fmt::Debug for __anon_Foo_4 {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         write!(f, "(???)")
     }
 }
-impl Default for __anon_4 {
+impl Default for __anon_Foo_4 {
     fn default() -> Self {
         Self {
             c: u8::default(),
@@ -2763,20 +2763,20 @@ struct Foo foo = {{0}};
 #[derive(Debug, Default, Copy, Clone)]
 #[repr(C)]
 pub struct Foo {
-    pub __anon_1: __anon_1,
+    pub __anon_Foo_1: __anon_Foo_1,
 }
 #[derive(Copy, Clone)]
 #[repr(C)]
-pub union __anon_1 {
+pub union __anon_Foo_1 {
     pub name: *mut i8,
     pub tp: *mut std::ffi::c_void,
 }
-impl std::fmt::Debug for __anon_1 {
+impl std::fmt::Debug for __anon_Foo_1 {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         write!(f, "(???)")
     }
 }
-impl Default for __anon_1 {
+impl Default for __anon_Foo_1 {
     fn default() -> Self {
         Self {
             name: std::ptr::null_mut(),
@@ -2792,6 +2792,134 @@ impl Default for __anon_1 {
     assert_definition(&btf, &struct_foo, expected_output);
 }
 
+#[test]
+fn test_btf_dump_anon_member_tree() {
+    let prog_text = r#"
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+
+struct Foo {
+    union {
+        struct {
+            char *name;
+            void *tp;
+        };
+        struct Bar {
+            union {
+                struct {
+                    char *name;
+                    void *trp;
+                };
+                struct Baz {
+                    char *name;
+                    void *trp;
+                } baz;
+            };
+        } bar;
+    };
+};
+
+struct Foo foo = {0};
+"#;
+
+    let expected_output = r#"
+#[derive(Debug, Default, Copy, Clone)]
+#[repr(C)]
+pub struct Foo {
+    pub __anon_Foo_1: __anon_Foo_1,
+}
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub union __anon_Foo_1 {
+    pub __anon_Foo_2: __anon_Foo_2,
+    pub bar: Bar,
+}
+impl std::fmt::Debug for __anon_Foo_1 {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "(???)")
+    }
+}
+impl Default for __anon_Foo_1 {
+    fn default() -> Self {
+        Self {
+            __anon_Foo_2: __anon_Foo_2::default(),
+        }
+    }
+}
+#[derive(Debug, Copy, Clone)]
+#[repr(C)]
+pub struct __anon_Foo_2 {
+    pub name: *mut i8,
+    pub tp: *mut std::ffi::c_void,
+}
+impl Default for __anon_Foo_2 {
+    fn default() -> Self {
+        Self {
+            name: std::ptr::null_mut(),
+            tp: std::ptr::null_mut(),
+        }
+    }
+}
+#[derive(Debug, Default, Copy, Clone)]
+#[repr(C)]
+pub struct Bar {
+    pub __anon_Bar_1: __anon_Bar_1,
+}
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub union __anon_Bar_1 {
+    pub __anon_Bar_2: __anon_Bar_2,
+    pub baz: Baz,
+}
+impl std::fmt::Debug for __anon_Bar_1 {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "(???)")
+    }
+}
+impl Default for __anon_Bar_1 {
+    fn default() -> Self {
+        Self {
+            __anon_Bar_2: __anon_Bar_2::default(),
+        }
+    }
+}
+#[derive(Debug, Copy, Clone)]
+#[repr(C)]
+pub struct __anon_Bar_2 {
+    pub name: *mut i8,
+    pub trp: *mut std::ffi::c_void,
+}
+impl Default for __anon_Bar_2 {
+    fn default() -> Self {
+        Self {
+            name: std::ptr::null_mut(),
+            trp: std::ptr::null_mut(),
+        }
+    }
+}
+#[derive(Debug, Copy, Clone)]
+#[repr(C)]
+pub struct Baz {
+    pub name: *mut i8,
+    pub trp: *mut std::ffi::c_void,
+}
+impl Default for Baz {
+    fn default() -> Self {
+        Self {
+            name: std::ptr::null_mut(),
+            trp: std::ptr::null_mut(),
+        }
+    }
+}
+"#;
+
+    let mmap = build_btf_mmap(prog_text);
+    let btf = btf_from_mmap(&mmap);
+    let struct_foo = find_type_in_btf!(btf, types::Struct<'_>, "Foo");
+
+    assert_definition(&btf, &struct_foo, expected_output);
+}
+
 #[test]
 fn test_btf_dump_definition_anon_enum() {
     let prog_text = r#"
@@ -2811,17 +2939,17 @@ struct Foo foo;
 #[derive(Debug, Default, Copy, Clone)]
 #[repr(C)]
 pub struct Foo {
-    pub test: __anon_1,
+    pub test: __anon_Foo_1,
 }
 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
 #[repr(transparent)]
-pub struct __anon_1(pub u32);
+pub struct __anon_Foo_1(pub u32);
 #[allow(non_upper_case_globals)]
-impl __anon_1 {
-    pub const FOO: __anon_1 = __anon_1(1);
+impl __anon_Foo_1 {
+    pub const FOO: __anon_Foo_1 = __anon_Foo_1(1);
 }
-impl Default for __anon_1 {
-    fn default() -> Self { __anon_1::FOO }
+impl Default for __anon_Foo_1 {
+    fn default() -> Self { __anon_Foo_1::FOO }
 }
 "#;
 
@@ -2918,40 +3046,40 @@ struct bpf_sock_tuple_5_15 tup;
 #[derive(Debug, Default, Copy, Clone)]
 #[repr(C)]
 pub struct bpf_sock_tuple_5_15 {
-    pub __anon_1: __anon_1,
+    pub __anon_bpf_sock_tuple_5_15_1: __anon_bpf_sock_tuple_5_15_1,
     pub __pad_36: [u8; 4],
-    pub __anon_2: __anon_2,
+    pub __anon_bpf_sock_tuple_5_15_2: __anon_bpf_sock_tuple_5_15_2,
 }
 #[derive(Copy, Clone)]
 #[repr(C)]
-pub union __anon_1 {
-    pub ipv4: __anon_3,
-    pub ipv6: __anon_4,
+pub union __anon_bpf_sock_tuple_5_15_1 {
+    pub ipv4: __anon_bpf_sock_tuple_5_15_3,
+    pub ipv6: __anon_bpf_sock_tuple_5_15_4,
 }
-impl std::fmt::Debug for __anon_1 {
+impl std::fmt::Debug for __anon_bpf_sock_tuple_5_15_1 {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         write!(f, "(???)")
     }
 }
-impl Default for __anon_1 {
+impl Default for __anon_bpf_sock_tuple_5_15_1 {
     fn default() -> Self {
         Self {
-            ipv4: __anon_3::default(),
+            ipv4: __anon_bpf_sock_tuple_5_15_3::default(),
         }
     }
 }
 #[derive(Copy, Clone)]
 #[repr(C)]
-pub union __anon_2 {
+pub union __anon_bpf_sock_tuple_5_15_2 {
     pub a: i32,
     pub b: *mut i8,
 }
-impl std::fmt::Debug for __anon_2 {
+impl std::fmt::Debug for __anon_bpf_sock_tuple_5_15_2 {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         write!(f, "(???)")
     }
 }
-impl Default for __anon_2 {
+impl Default for __anon_bpf_sock_tuple_5_15_2 {
     fn default() -> Self {
         Self {
             a: i32::default(),
@@ -2960,7 +3088,7 @@ impl Default for __anon_2 {
 }
 #[derive(Debug, Default, Copy, Clone)]
 #[repr(C)]
-pub struct __anon_3 {
+pub struct __anon_bpf_sock_tuple_5_15_3 {
     pub saddr: u32,
     pub daddr: u32,
     pub sport: u16,
@@ -2968,7 +3096,7 @@ pub struct __anon_3 {
 }
 #[derive(Debug, Default, Copy, Clone)]
 #[repr(C)]
-pub struct __anon_4 {
+pub struct __anon_bpf_sock_tuple_5_15_4 {
     pub saddr: [u32; 4],
     pub daddr: [u32; 4],
     pub sport: u16,