diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
index d3c86989440e6..71a5727ed6cdb 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
@@ -1,9 +1,8 @@
-use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
+use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_errors::codes::*;
 use rustc_errors::struct_span_code_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::DefId;
 use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS;
 use rustc_middle::span_bug;
 use rustc_middle::ty::fold::BottomUpFolder;
@@ -11,7 +10,7 @@ use rustc_middle::ty::{
     self, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable,
     TypeVisitableExt, Upcast,
 };
-use rustc_span::{ErrorGuaranteed, Span};
+use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
 use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility;
 use rustc_trait_selection::traits::{self, hir_ty_lowering_dyn_compatibility_violations};
 use rustc_type_ir::elaborate::ClauseWithSupertraitSpan;
@@ -128,8 +127,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
         }
 
-        let mut associated_types: FxIndexMap<Span, FxIndexSet<DefId>> = FxIndexMap::default();
+        let mut needed_associated_types = FxIndexSet::default();
 
+        let principal_span = regular_traits.first().map_or(DUMMY_SP, |info| info.bottom().1);
         let regular_traits_refs_spans = trait_bounds
             .into_iter()
             .filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
@@ -145,13 +145,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 let bound_predicate = pred.kind();
                 match bound_predicate.skip_binder() {
                     ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
-                        let pred = bound_predicate.rebind(pred);
-                        associated_types.entry(original_span).or_default().extend(
-                            tcx.associated_items(pred.def_id())
+                        // FIXME(negative_bounds): Handle this correctly...
+                        let trait_ref =
+                            tcx.anonymize_bound_vars(bound_predicate.rebind(pred.trait_ref));
+                        needed_associated_types.extend(
+                            tcx.associated_items(trait_ref.def_id())
                                 .in_definition_order()
                                 .filter(|item| item.kind == ty::AssocKind::Type)
                                 .filter(|item| !item.is_impl_trait_in_trait())
-                                .map(|item| item.def_id),
+                                // If the associated type has a `where Self: Sized` bound,
+                                // we do not need to constrain the associated type.
+                                .filter(|item| !tcx.generics_require_sized_self(item.def_id))
+                                .map(|item| (item.def_id, trait_ref)),
                         );
                     }
                     ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
@@ -201,26 +206,25 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         // So every `Projection` clause is an `Assoc = Foo` bound. `associated_types` contains all associated
         // types's `DefId`, so the following loop removes all the `DefIds` of the associated types that have a
         // corresponding `Projection` clause
-        for def_ids in associated_types.values_mut() {
-            for (projection_bound, span) in &projection_bounds {
-                let def_id = projection_bound.item_def_id();
-                def_ids.swap_remove(&def_id);
-                if tcx.generics_require_sized_self(def_id) {
-                    tcx.emit_node_span_lint(
-                        UNUSED_ASSOCIATED_TYPE_BOUNDS,
-                        hir_id,
-                        *span,
-                        crate::errors::UnusedAssociatedTypeBounds { span: *span },
-                    );
-                }
+        for (projection_bound, span) in &projection_bounds {
+            let def_id = projection_bound.item_def_id();
+            let trait_ref = tcx.anonymize_bound_vars(
+                projection_bound.map_bound(|p| p.projection_term.trait_ref(tcx)),
+            );
+            needed_associated_types.swap_remove(&(def_id, trait_ref));
+            if tcx.generics_require_sized_self(def_id) {
+                tcx.emit_node_span_lint(
+                    UNUSED_ASSOCIATED_TYPE_BOUNDS,
+                    hir_id,
+                    *span,
+                    crate::errors::UnusedAssociatedTypeBounds { span: *span },
+                );
             }
-            // If the associated type has a `where Self: Sized` bound, we do not need to constrain the associated
-            // type in the `dyn Trait`.
-            def_ids.retain(|def_id| !tcx.generics_require_sized_self(def_id));
         }
 
         if let Err(guar) = self.check_for_required_assoc_tys(
-            associated_types,
+            principal_span,
+            needed_associated_types,
             potential_assoc_types,
             hir_trait_bounds,
         ) {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
index 2e227ead14a93..a66b0b322382b 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -722,51 +722,42 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     /// emit a generic note suggesting using a `where` clause to constraint instead.
     pub(crate) fn check_for_required_assoc_tys(
         &self,
-        associated_types: FxIndexMap<Span, FxIndexSet<DefId>>,
+        principal_span: Span,
+        missing_assoc_types: FxIndexSet<(DefId, ty::PolyTraitRef<'tcx>)>,
         potential_assoc_types: Vec<usize>,
         trait_bounds: &[hir::PolyTraitRef<'_>],
     ) -> Result<(), ErrorGuaranteed> {
-        if associated_types.values().all(|v| v.is_empty()) {
+        if missing_assoc_types.is_empty() {
             return Ok(());
         }
 
         let tcx = self.tcx();
-        // FIXME: Marked `mut` so that we can replace the spans further below with a more
-        // appropriate one, but this should be handled earlier in the span assignment.
-        let associated_types: FxIndexMap<Span, Vec<_>> = associated_types
+        // FIXME: This logic needs some more care w.r.t handling of conflicts
+        let missing_assoc_types: Vec<_> = missing_assoc_types
             .into_iter()
-            .map(|(span, def_ids)| {
-                (span, def_ids.into_iter().map(|did| tcx.associated_item(did)).collect())
-            })
+            .map(|(def_id, trait_ref)| (tcx.associated_item(def_id), trait_ref))
             .collect();
-        let mut names: FxIndexMap<String, Vec<Symbol>> = Default::default();
+        let mut names: FxIndexMap<_, Vec<Symbol>> = Default::default();
         let mut names_len = 0;
 
         // Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and
         // `issue-22560.rs`.
-        let mut trait_bound_spans: Vec<Span> = vec![];
         let mut dyn_compatibility_violations = Ok(());
-        for (span, items) in &associated_types {
-            if !items.is_empty() {
-                trait_bound_spans.push(*span);
-            }
-            for assoc_item in items {
-                let trait_def_id = assoc_item.container_id(tcx);
-                names.entry(tcx.def_path_str(trait_def_id)).or_default().push(assoc_item.name);
-                names_len += 1;
-
-                let violations =
-                    dyn_compatibility_violations_for_assoc_item(tcx, trait_def_id, *assoc_item);
-                if !violations.is_empty() {
-                    dyn_compatibility_violations = Err(report_dyn_incompatibility(
-                        tcx,
-                        *span,
-                        None,
-                        trait_def_id,
-                        &violations,
-                    )
-                    .emit());
-                }
+        for (assoc_item, trait_ref) in &missing_assoc_types {
+            names.entry(trait_ref).or_default().push(assoc_item.name);
+            names_len += 1;
+
+            let violations =
+                dyn_compatibility_violations_for_assoc_item(tcx, trait_ref.def_id(), *assoc_item);
+            if !violations.is_empty() {
+                dyn_compatibility_violations = Err(report_dyn_incompatibility(
+                    tcx,
+                    principal_span,
+                    None,
+                    trait_ref.def_id(),
+                    &violations,
+                )
+                .emit());
             }
         }
 
@@ -814,6 +805,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             .into_iter()
             .map(|(trait_, mut assocs)| {
                 assocs.sort();
+                let trait_ = trait_.print_trait_sugared();
                 format!("{} in `{trait_}`", match &assocs[..] {
                     [] => String::new(),
                     [only] => format!("`{only}`"),
@@ -827,10 +819,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         names.sort();
         let names = names.join(", ");
 
-        trait_bound_spans.sort();
         let mut err = struct_span_code_err!(
             self.dcx(),
-            trait_bound_spans,
+            principal_span,
             E0191,
             "the value of the associated type{} {} must be specified",
             pluralize!(names_len),
@@ -840,81 +831,83 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let mut types_count = 0;
         let mut where_constraints = vec![];
         let mut already_has_generics_args_suggestion = false;
-        for (span, assoc_items) in &associated_types {
-            let mut names: UnordMap<_, usize> = Default::default();
-            for item in assoc_items {
-                types_count += 1;
-                *names.entry(item.name).or_insert(0) += 1;
-            }
-            let mut dupes = false;
-            let mut shadows = false;
-            for item in assoc_items {
-                let prefix = if names[&item.name] > 1 {
-                    let trait_def_id = item.container_id(tcx);
-                    dupes = true;
-                    format!("{}::", tcx.def_path_str(trait_def_id))
-                } else if bound_names.get(&item.name).is_some_and(|x| x != &item) {
-                    let trait_def_id = item.container_id(tcx);
-                    shadows = true;
-                    format!("{}::", tcx.def_path_str(trait_def_id))
-                } else {
-                    String::new()
-                };
 
-                let mut is_shadowed = false;
-
-                if let Some(assoc_item) = bound_names.get(&item.name)
-                    && assoc_item != &item
-                {
-                    is_shadowed = true;
+        let mut names: UnordMap<_, usize> = Default::default();
+        for (item, _) in &missing_assoc_types {
+            types_count += 1;
+            *names.entry(item.name).or_insert(0) += 1;
+        }
+        let mut dupes = false;
+        let mut shadows = false;
+        for (item, trait_ref) in &missing_assoc_types {
+            let prefix = if names[&item.name] > 1 {
+                let trait_def_id = trait_ref.def_id();
+                dupes = true;
+                format!("{}::", tcx.def_path_str(trait_def_id))
+            } else if bound_names.get(&item.name).is_some_and(|x| *x != item) {
+                let trait_def_id = trait_ref.def_id();
+                shadows = true;
+                format!("{}::", tcx.def_path_str(trait_def_id))
+            } else {
+                String::new()
+            };
 
-                    let rename_message =
-                        if assoc_item.def_id.is_local() { ", consider renaming it" } else { "" };
-                    err.span_label(
-                        tcx.def_span(assoc_item.def_id),
-                        format!("`{}{}` shadowed here{}", prefix, item.name, rename_message),
-                    );
-                }
+            let mut is_shadowed = false;
 
-                let rename_message = if is_shadowed { ", consider renaming it" } else { "" };
+            if let Some(assoc_item) = bound_names.get(&item.name)
+                && *assoc_item != item
+            {
+                is_shadowed = true;
 
-                if let Some(sp) = tcx.hir().span_if_local(item.def_id) {
-                    err.span_label(
-                        sp,
-                        format!("`{}{}` defined here{}", prefix, item.name, rename_message),
-                    );
-                }
+                let rename_message =
+                    if assoc_item.def_id.is_local() { ", consider renaming it" } else { "" };
+                err.span_label(
+                    tcx.def_span(assoc_item.def_id),
+                    format!("`{}{}` shadowed here{}", prefix, item.name, rename_message),
+                );
             }
-            if potential_assoc_types.len() == assoc_items.len() {
-                // When the amount of missing associated types equals the number of
-                // extra type arguments present. A suggesting to replace the generic args with
-                // associated types is already emitted.
-                already_has_generics_args_suggestion = true;
-            } else if let (Ok(snippet), false, false) =
-                (tcx.sess.source_map().span_to_snippet(*span), dupes, shadows)
-            {
-                let types: Vec<_> =
-                    assoc_items.iter().map(|item| format!("{} = Type", item.name)).collect();
-                let code = if snippet.ends_with('>') {
-                    // The user wrote `Trait<'a>` or similar and we don't have a type we can
-                    // suggest, but at least we can clue them to the correct syntax
-                    // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the
-                    // suggestion.
-                    format!("{}, {}>", &snippet[..snippet.len() - 1], types.join(", "))
-                } else if in_expr_or_pat {
-                    // The user wrote `Iterator`, so we don't have a type we can suggest, but at
-                    // least we can clue them to the correct syntax `Iterator::<Item = Type>`.
-                    format!("{}::<{}>", snippet, types.join(", "))
-                } else {
-                    // The user wrote `Iterator`, so we don't have a type we can suggest, but at
-                    // least we can clue them to the correct syntax `Iterator<Item = Type>`.
-                    format!("{}<{}>", snippet, types.join(", "))
-                };
-                suggestions.push((*span, code));
-            } else if dupes {
-                where_constraints.push(*span);
+
+            let rename_message = if is_shadowed { ", consider renaming it" } else { "" };
+
+            if let Some(sp) = tcx.hir().span_if_local(item.def_id) {
+                err.span_label(
+                    sp,
+                    format!("`{}{}` defined here{}", prefix, item.name, rename_message),
+                );
             }
         }
+        if potential_assoc_types.len() == missing_assoc_types.len() {
+            // When the amount of missing associated types equals the number of
+            // extra type arguments present. A suggesting to replace the generic args with
+            // associated types is already emitted.
+            already_has_generics_args_suggestion = true;
+        } else if let (Ok(snippet), false, false) =
+            (tcx.sess.source_map().span_to_snippet(principal_span), dupes, shadows)
+        {
+            let types: Vec<_> = missing_assoc_types
+                .iter()
+                .map(|(item, _)| format!("{} = Type", item.name))
+                .collect();
+            let code = if snippet.ends_with('>') {
+                // The user wrote `Trait<'a>` or similar and we don't have a type we can
+                // suggest, but at least we can clue them to the correct syntax
+                // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the
+                // suggestion.
+                format!("{}, {}>", &snippet[..snippet.len() - 1], types.join(", "))
+            } else if in_expr_or_pat {
+                // The user wrote `Iterator`, so we don't have a type we can suggest, but at
+                // least we can clue them to the correct syntax `Iterator::<Item = Type>`.
+                format!("{}::<{}>", snippet, types.join(", "))
+            } else {
+                // The user wrote `Iterator`, so we don't have a type we can suggest, but at
+                // least we can clue them to the correct syntax `Iterator<Item = Type>`.
+                format!("{}<{}>", snippet, types.join(", "))
+            };
+            suggestions.push((principal_span, code));
+        } else if dupes {
+            where_constraints.push(principal_span);
+        }
+
         let where_msg = "consider introducing a new type parameter, adding `where` constraints \
                          using the fully-qualified path to the associated types";
         if !where_constraints.is_empty() && suggestions.is_empty() {
@@ -925,32 +918,29 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         }
         if suggestions.len() != 1 || already_has_generics_args_suggestion {
             // We don't need this label if there's an inline suggestion, show otherwise.
-            for (span, assoc_items) in &associated_types {
-                let mut names: FxIndexMap<_, usize> = FxIndexMap::default();
-                for item in assoc_items {
-                    types_count += 1;
-                    *names.entry(item.name).or_insert(0) += 1;
-                }
-                let mut label = vec![];
-                for item in assoc_items {
-                    let postfix = if names[&item.name] > 1 {
-                        let trait_def_id = item.container_id(tcx);
-                        format!(" (from trait `{}`)", tcx.def_path_str(trait_def_id))
-                    } else {
-                        String::new()
-                    };
-                    label.push(format!("`{}`{}", item.name, postfix));
-                }
-                if !label.is_empty() {
-                    err.span_label(
-                        *span,
-                        format!(
-                            "associated type{} {} must be specified",
-                            pluralize!(label.len()),
-                            label.join(", "),
-                        ),
-                    );
-                }
+            let mut names: FxIndexMap<_, usize> = FxIndexMap::default();
+            for (item, _) in &missing_assoc_types {
+                types_count += 1;
+                *names.entry(item.name).or_insert(0) += 1;
+            }
+            let mut label = vec![];
+            for (item, trait_ref) in &missing_assoc_types {
+                let postfix = if names[&item.name] > 1 {
+                    format!(" (from trait `{}`)", trait_ref.print_trait_sugared())
+                } else {
+                    String::new()
+                };
+                label.push(format!("`{}`{}", item.name, postfix));
+            }
+            if !label.is_empty() {
+                err.span_label(
+                    principal_span,
+                    format!(
+                        "associated type{} {} must be specified",
+                        pluralize!(label.len()),
+                        label.join(", "),
+                    ),
+                );
             }
         }
         suggestions.sort_by_key(|&(span, _)| span);
diff --git a/tests/ui/associated-types/missing-associated-types.stderr b/tests/ui/associated-types/missing-associated-types.stderr
index ce4b57e8af813..3a56c55896ebf 100644
--- a/tests/ui/associated-types/missing-associated-types.stderr
+++ b/tests/ui/associated-types/missing-associated-types.stderr
@@ -42,11 +42,11 @@ LL | type Bat<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Fine<Rhs>;
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add<Rhs> + Sub<Rhs> + Fine<Rhs> {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
-error[E0191]: the value of the associated types `Output` in `Div`, `Output` in `Mul` must be specified
+error[E0191]: the value of the associated types `Output` in `Div<Rhs>`, `Output` in `Mul<Rhs>` must be specified
   --> $DIR/missing-associated-types.rs:20:21
    |
 LL | type Bal<Rhs> = dyn X<Rhs>;
-   |                     ^^^^^^ associated types `Output` (from trait `Div`), `Output` (from trait `Mul`) must be specified
+   |                     ^^^^^^ associated types `Output` (from trait `Div<Rhs>`), `Output` (from trait `Mul<Rhs>`) must be specified
    |
    = help: consider introducing a new type parameter, adding `where` constraints using the fully-qualified path to the associated types
 
diff --git a/tests/ui/dyn-compatibility/assoc_type_bounds.rs b/tests/ui/dyn-compatibility/assoc_type_bounds.rs
index 8634ba626a18a..6e2076a482247 100644
--- a/tests/ui/dyn-compatibility/assoc_type_bounds.rs
+++ b/tests/ui/dyn-compatibility/assoc_type_bounds.rs
@@ -7,7 +7,7 @@ trait Foo<T> {
 trait Cake {}
 impl Cake for () {}
 
-fn foo(_: &dyn Foo<()>) {} //~ ERROR: the value of the associated type `Bar` in `Foo` must be specified
-fn bar(_: &dyn Foo<i32>) {} //~ ERROR: the value of the associated type `Bar` in `Foo` must be specified
+fn foo(_: &dyn Foo<()>) {} //~ ERROR: the value of the associated type `Bar` in `Foo<()>` must be specified
+fn bar(_: &dyn Foo<i32>) {} //~ ERROR: the value of the associated type `Bar` in `Foo<i32>` must be specified
 
 fn main() {}
diff --git a/tests/ui/dyn-compatibility/assoc_type_bounds.stderr b/tests/ui/dyn-compatibility/assoc_type_bounds.stderr
index 3d5482625af3e..21ba903011739 100644
--- a/tests/ui/dyn-compatibility/assoc_type_bounds.stderr
+++ b/tests/ui/dyn-compatibility/assoc_type_bounds.stderr
@@ -1,4 +1,4 @@
-error[E0191]: the value of the associated type `Bar` in `Foo` must be specified
+error[E0191]: the value of the associated type `Bar` in `Foo<()>` must be specified
   --> $DIR/assoc_type_bounds.rs:10:16
    |
 LL |     type Bar
@@ -7,7 +7,7 @@ LL |     type Bar
 LL | fn foo(_: &dyn Foo<()>) {}
    |                ^^^^^^^ help: specify the associated type: `Foo<(), Bar = Type>`
 
-error[E0191]: the value of the associated type `Bar` in `Foo` must be specified
+error[E0191]: the value of the associated type `Bar` in `Foo<i32>` must be specified
   --> $DIR/assoc_type_bounds.rs:11:16
    |
 LL |     type Bar
diff --git a/tests/ui/dyn-compatibility/assoc_type_bounds2.rs b/tests/ui/dyn-compatibility/assoc_type_bounds2.rs
index f7dc2fb88390f..2b35016d774ce 100644
--- a/tests/ui/dyn-compatibility/assoc_type_bounds2.rs
+++ b/tests/ui/dyn-compatibility/assoc_type_bounds2.rs
@@ -7,7 +7,7 @@ trait Foo<T> {
 trait Cake {}
 impl Cake for () {}
 
-fn foo(_: &dyn Foo<()>) {} //~ ERROR: the value of the associated type `Bar` in `Foo` must be specified
-fn bar(_: &dyn Foo<i32>) {} //~ ERROR: the value of the associated type `Bar` in `Foo` must be specified
+fn foo(_: &dyn Foo<()>) {} //~ ERROR: the value of the associated type `Bar` in `Foo<()>` must be specified
+fn bar(_: &dyn Foo<i32>) {} //~ ERROR: the value of the associated type `Bar` in `Foo<i32>` must be specified
 
 fn main() {}
diff --git a/tests/ui/dyn-compatibility/assoc_type_bounds2.stderr b/tests/ui/dyn-compatibility/assoc_type_bounds2.stderr
index 815747436bf0d..5c4163b196936 100644
--- a/tests/ui/dyn-compatibility/assoc_type_bounds2.stderr
+++ b/tests/ui/dyn-compatibility/assoc_type_bounds2.stderr
@@ -1,4 +1,4 @@
-error[E0191]: the value of the associated type `Bar` in `Foo` must be specified
+error[E0191]: the value of the associated type `Bar` in `Foo<()>` must be specified
   --> $DIR/assoc_type_bounds2.rs:10:16
    |
 LL |     type Bar
@@ -7,7 +7,7 @@ LL |     type Bar
 LL | fn foo(_: &dyn Foo<()>) {}
    |                ^^^^^^^ help: specify the associated type: `Foo<(), Bar = Type>`
 
-error[E0191]: the value of the associated type `Bar` in `Foo` must be specified
+error[E0191]: the value of the associated type `Bar` in `Foo<i32>` must be specified
   --> $DIR/assoc_type_bounds2.rs:11:16
    |
 LL |     type Bar
diff --git a/tests/ui/dyn-compatibility/require-assoc-for-all-super-substs.rs b/tests/ui/dyn-compatibility/require-assoc-for-all-super-substs.rs
new file mode 100644
index 0000000000000..1f4e1bf653a3f
--- /dev/null
+++ b/tests/ui/dyn-compatibility/require-assoc-for-all-super-substs.rs
@@ -0,0 +1,15 @@
+trait Sup<T> {
+    type Assoc: Default;
+}
+
+impl<T: Default> Sup<T> for () {
+    type Assoc = T;
+}
+impl<T: Default, U: Default> Dyn<T, U> for () {}
+
+trait Dyn<A, B>: Sup<A, Assoc = A> + Sup<B> {}
+
+fn main() {
+    let q: <dyn Dyn<i32, u32> as Sup<u32>>::Assoc = Default::default();
+    //~^ ERROR the value of the associated type `Assoc` in `Sup<u32>` must be specified
+}
diff --git a/tests/ui/dyn-compatibility/require-assoc-for-all-super-substs.stderr b/tests/ui/dyn-compatibility/require-assoc-for-all-super-substs.stderr
new file mode 100644
index 0000000000000..3d89b52d522db
--- /dev/null
+++ b/tests/ui/dyn-compatibility/require-assoc-for-all-super-substs.stderr
@@ -0,0 +1,12 @@
+error[E0191]: the value of the associated type `Assoc` in `Sup<u32>` must be specified
+  --> $DIR/require-assoc-for-all-super-substs.rs:13:17
+   |
+LL |     type Assoc: Default;
+   |     ------------------- `Assoc` defined here
+...
+LL |     let q: <dyn Dyn<i32, u32> as Sup<u32>>::Assoc = Default::default();
+   |                 ^^^^^^^^^^^^^ help: specify the associated type: `Dyn<i32, u32, Assoc = Type>`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0191`.
diff --git a/tests/ui/issues/issue-28344.stderr b/tests/ui/issues/issue-28344.stderr
index d8febe7165241..7bc965536e9a1 100644
--- a/tests/ui/issues/issue-28344.stderr
+++ b/tests/ui/issues/issue-28344.stderr
@@ -12,7 +12,7 @@ help: if this is a dyn-compatible trait, use `dyn`
 LL |     let x: u8 = <dyn BitXor>::bitor(0 as u8, 0 as u8);
    |                 ++++       +
 
-error[E0191]: the value of the associated type `Output` in `BitXor` must be specified
+error[E0191]: the value of the associated type `Output` in `BitXor<_>` must be specified
   --> $DIR/issue-28344.rs:4:17
    |
 LL |     let x: u8 = BitXor::bitor(0 as u8, 0 as u8);
@@ -31,7 +31,7 @@ help: if this is a dyn-compatible trait, use `dyn`
 LL |     let g = <dyn BitXor>::bitor;
    |             ++++       +
 
-error[E0191]: the value of the associated type `Output` in `BitXor` must be specified
+error[E0191]: the value of the associated type `Output` in `BitXor<_>` must be specified
   --> $DIR/issue-28344.rs:9:13
    |
 LL |     let g = BitXor::bitor;