diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 96aae3bd70cd2..f1c7c1ea852a2 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -628,6 +628,7 @@ impl<T> Trait<T> for X {
                             assoc_substs,
                             ty,
                             msg,
+                            false,
                         ) {
                             return true;
                         }
@@ -646,6 +647,7 @@ impl<T> Trait<T> for X {
                             assoc_substs,
                             ty,
                             msg,
+                            false,
                         );
                     }
                 }
@@ -771,13 +773,24 @@ fn foo(&self) -> Self::T { String::new() }
     ) -> bool {
         let assoc = self.associated_item(proj_ty.item_def_id);
         if let ty::Opaque(def_id, _) = *proj_ty.self_ty().kind() {
-            self.constrain_associated_type_structured_suggestion(
+            let opaque_local_def_id = def_id.expect_local();
+            let opaque_hir_id = self.hir().local_def_id_to_hir_id(opaque_local_def_id);
+            let opaque_hir_ty = match &self.hir().expect_item(opaque_hir_id).kind {
+                hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty,
+                _ => bug!("The HirId comes from a `ty::Opaque`"),
+            };
+
+            let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self);
+
+            self.constrain_generic_bound_associated_type_structured_suggestion(
                 db,
-                self.def_span(def_id),
-                &assoc,
-                proj_ty.trait_ref_and_own_substs(self).1,
+                &trait_ref,
+                opaque_hir_ty.bounds,
+                assoc,
+                assoc_substs,
                 ty,
-                &msg,
+                msg,
+                true,
             )
         } else {
             false
@@ -899,6 +912,11 @@ fn foo(&self) -> Self::T { String::new() }
 
     /// Given a slice of `hir::GenericBound`s, if any of them corresponds to the `trait_ref`
     /// requirement, provide a structured suggestion to constrain it to a given type `ty`.
+    ///
+    /// `is_bound_surely_present` indicates whether we know the bound we're looking for is
+    /// inside `bounds`. If that's the case then we can consider `bounds` containing only one
+    /// trait bound as the one we're looking for. This can help in cases where the associated
+    /// type is defined on a supertrait of the one present in the bounds.
     fn constrain_generic_bound_associated_type_structured_suggestion(
         self,
         db: &mut DiagnosticBuilder<'_>,
@@ -908,23 +926,30 @@ fn foo(&self) -> Self::T { String::new() }
         assoc_substs: &[ty::GenericArg<'tcx>],
         ty: Ty<'tcx>,
         msg: &str,
+        is_bound_surely_present: bool,
     ) -> bool {
         // FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting.
-        bounds.iter().any(|bound| match bound {
-            hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::None) => {
-                // Relate the type param against `T` in `<A as T>::Foo`.
-                ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id)
-                    && self.constrain_associated_type_structured_suggestion(
-                        db,
-                        ptr.span,
-                        assoc,
-                        assoc_substs,
-                        ty,
-                        msg,
-                    )
-            }
-            _ => false,
-        })
+
+        let trait_bounds = bounds.iter().filter_map(|bound| match bound {
+            hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::None) => Some(ptr),
+            _ => None,
+        });
+
+        let matching_trait_bounds = trait_bounds
+            .clone()
+            .filter(|ptr| ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id))
+            .collect::<Vec<_>>();
+
+        let span = match &matching_trait_bounds[..] {
+            &[ptr] => ptr.span,
+            &[] if is_bound_surely_present => match &trait_bounds.collect::<Vec<_>>()[..] {
+                &[ptr] => ptr.span,
+                _ => return false,
+            },
+            _ => return false,
+        };
+
+        self.constrain_associated_type_structured_suggestion(db, span, assoc, assoc_substs, ty, msg)
     }
 
     /// Given a span corresponding to a bound, provide a structured suggestion to set an
diff --git a/src/test/ui/associated-types/issue-87261.rs b/src/test/ui/associated-types/issue-87261.rs
new file mode 100644
index 0000000000000..a70f771e4826f
--- /dev/null
+++ b/src/test/ui/associated-types/issue-87261.rs
@@ -0,0 +1,99 @@
+trait Foo {}
+
+trait Trait {
+    type Associated;
+}
+trait DerivedTrait: Trait {}
+trait GenericTrait<A> {
+    type Associated;
+}
+
+struct Impl;
+impl Foo for Impl {}
+impl Trait for Impl {
+    type Associated = ();
+}
+impl DerivedTrait for Impl {}
+impl<A> GenericTrait<A> for Impl {
+    type Associated = ();
+}
+
+fn returns_opaque() -> impl Trait + 'static {
+    Impl
+}
+fn returns_opaque_derived() -> impl DerivedTrait + 'static {
+    Impl
+}
+fn returns_opaque_foo() -> impl Trait + Foo {
+    Impl
+}
+fn returns_opaque_derived_foo() -> impl DerivedTrait + Foo {
+    Impl
+}
+fn returns_opaque_generic() -> impl GenericTrait<()> + 'static {
+    Impl
+}
+fn returns_opaque_generic_foo() -> impl GenericTrait<()> + Foo {
+    Impl
+}
+fn returns_opaque_generic_duplicate() -> impl GenericTrait<()> + GenericTrait<u8> {
+    Impl
+}
+
+fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
+fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
+
+fn check_generics<A, B, C, D, E, F, G>(a: A, b: B, c: C, d: D, e: E, f: F, g: G)
+where
+    A: Trait + 'static,
+    B: DerivedTrait + 'static,
+    C: Trait + Foo,
+    D: DerivedTrait + Foo,
+    E: GenericTrait<()> + 'static,
+    F: GenericTrait<()> + Foo,
+    G: GenericTrait<()> + GenericTrait<u8>,
+{
+    accepts_trait(a);
+    //~^ ERROR type mismatch resolving `<A as Trait>::Associated == ()`
+
+    accepts_trait(b);
+    //~^ ERROR type mismatch resolving `<B as Trait>::Associated == ()`
+
+    accepts_trait(c);
+    //~^ ERROR type mismatch resolving `<C as Trait>::Associated == ()`
+
+    accepts_trait(d);
+    //~^ ERROR type mismatch resolving `<D as Trait>::Associated == ()`
+
+    accepts_generic_trait(e);
+    //~^ ERROR type mismatch resolving `<E as GenericTrait<()>>::Associated == ()`
+
+    accepts_generic_trait(f);
+    //~^ ERROR type mismatch resolving `<F as GenericTrait<()>>::Associated == ()`
+
+    accepts_generic_trait(g);
+    //~^ ERROR type mismatch resolving `<G as GenericTrait<()>>::Associated == ()`
+}
+
+fn main() {
+    accepts_trait(returns_opaque());
+    //~^ ERROR type mismatch resolving `<impl Trait as Trait>::Associated == ()`
+
+    accepts_trait(returns_opaque_derived());
+    //~^ ERROR type mismatch resolving `<impl DerivedTrait as Trait>::Associated == ()`
+
+    accepts_trait(returns_opaque_foo());
+    //~^ ERROR type mismatch resolving `<impl Trait+Foo as Trait>::Associated == ()`
+
+    accepts_trait(returns_opaque_derived_foo());
+    //~^ ERROR type mismatch resolving `<impl DerivedTrait+Foo as Trait>::Associated == ()`
+
+    accepts_generic_trait(returns_opaque_generic());
+    //~^ ERROR type mismatch resolving `<impl GenericTrait<()> as GenericTrait<()>>::Associated == ()`
+
+    accepts_generic_trait(returns_opaque_generic_foo());
+    //~^ ERROR type mismatch resolving `<impl GenericTrait<()>+Foo as GenericTrait<()>>::Associated == ()`
+
+    accepts_generic_trait(returns_opaque_generic_duplicate());
+    //~^ ERROR type mismatch resolving `<impl GenericTrait<()>+GenericTrait<u8> as GenericTrait<()>>::Associated == ()`
+}
diff --git a/src/test/ui/associated-types/issue-87261.stderr b/src/test/ui/associated-types/issue-87261.stderr
new file mode 100644
index 0000000000000..0725acfe537db
--- /dev/null
+++ b/src/test/ui/associated-types/issue-87261.stderr
@@ -0,0 +1,238 @@
+error[E0271]: type mismatch resolving `<A as Trait>::Associated == ()`
+  --> $DIR/issue-87261.rs:56:5
+   |
+LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
+   |                           --------------- required by this bound in `accepts_trait`
+...
+LL |     accepts_trait(a);
+   |     ^^^^^^^^^^^^^ expected `()`, found associated type
+   |
+   = note:    expected unit type `()`
+           found associated type `<A as Trait>::Associated`
+help: consider constraining the associated type `<A as Trait>::Associated` to `()`
+   |
+LL |     A: Trait<Associated = ()> + 'static,
+   |             ^^^^^^^^^^^^^^^^^
+
+error[E0271]: type mismatch resolving `<B as Trait>::Associated == ()`
+  --> $DIR/issue-87261.rs:59:5
+   |
+LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
+   |                           --------------- required by this bound in `accepts_trait`
+...
+LL |     accepts_trait(b);
+   |     ^^^^^^^^^^^^^ expected `()`, found associated type
+   |
+   = note:    expected unit type `()`
+           found associated type `<B as Trait>::Associated`
+   = help: consider constraining the associated type `<B as Trait>::Associated` to `()`
+   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+
+error[E0271]: type mismatch resolving `<C as Trait>::Associated == ()`
+  --> $DIR/issue-87261.rs:62:5
+   |
+LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
+   |                           --------------- required by this bound in `accepts_trait`
+...
+LL |     accepts_trait(c);
+   |     ^^^^^^^^^^^^^ expected `()`, found associated type
+   |
+   = note:    expected unit type `()`
+           found associated type `<C as Trait>::Associated`
+help: consider constraining the associated type `<C as Trait>::Associated` to `()`
+   |
+LL |     C: Trait<Associated = ()> + Foo,
+   |             ^^^^^^^^^^^^^^^^^
+
+error[E0271]: type mismatch resolving `<D as Trait>::Associated == ()`
+  --> $DIR/issue-87261.rs:65:5
+   |
+LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
+   |                           --------------- required by this bound in `accepts_trait`
+...
+LL |     accepts_trait(d);
+   |     ^^^^^^^^^^^^^ expected `()`, found associated type
+   |
+   = note:    expected unit type `()`
+           found associated type `<D as Trait>::Associated`
+   = help: consider constraining the associated type `<D as Trait>::Associated` to `()`
+   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+
+error[E0271]: type mismatch resolving `<E as GenericTrait<()>>::Associated == ()`
+  --> $DIR/issue-87261.rs:68:5
+   |
+LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
+   |                                              --------------- required by this bound in `accepts_generic_trait`
+...
+LL |     accepts_generic_trait(e);
+   |     ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
+   |
+   = note:    expected unit type `()`
+           found associated type `<E as GenericTrait<()>>::Associated`
+help: consider constraining the associated type `<E as GenericTrait<()>>::Associated` to `()`
+   |
+LL |     E: GenericTrait<(), Associated = ()> + 'static,
+   |                       ^^^^^^^^^^^^^^^^^
+
+error[E0271]: type mismatch resolving `<F as GenericTrait<()>>::Associated == ()`
+  --> $DIR/issue-87261.rs:71:5
+   |
+LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
+   |                                              --------------- required by this bound in `accepts_generic_trait`
+...
+LL |     accepts_generic_trait(f);
+   |     ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
+   |
+   = note:    expected unit type `()`
+           found associated type `<F as GenericTrait<()>>::Associated`
+help: consider constraining the associated type `<F as GenericTrait<()>>::Associated` to `()`
+   |
+LL |     F: GenericTrait<(), Associated = ()> + Foo,
+   |                       ^^^^^^^^^^^^^^^^^
+
+error[E0271]: type mismatch resolving `<G as GenericTrait<()>>::Associated == ()`
+  --> $DIR/issue-87261.rs:74:5
+   |
+LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
+   |                                              --------------- required by this bound in `accepts_generic_trait`
+...
+LL |     accepts_generic_trait(g);
+   |     ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
+   |
+   = note:    expected unit type `()`
+           found associated type `<G as GenericTrait<()>>::Associated`
+   = help: consider constraining the associated type `<G as GenericTrait<()>>::Associated` to `()`
+   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+
+error[E0271]: type mismatch resolving `<impl Trait as Trait>::Associated == ()`
+  --> $DIR/issue-87261.rs:79:5
+   |
+LL | fn returns_opaque() -> impl Trait + 'static {
+   |                        -------------------- the found opaque type
+...
+LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
+   |                           --------------- required by this bound in `accepts_trait`
+...
+LL |     accepts_trait(returns_opaque());
+   |     ^^^^^^^^^^^^^ expected `()`, found associated type
+   |
+   = note:    expected unit type `()`
+           found associated type `<impl Trait as Trait>::Associated`
+help: consider constraining the associated type `<impl Trait as Trait>::Associated` to `()`
+   |
+LL | fn returns_opaque() -> impl Trait<Associated = ()> + 'static {
+   |                                  ^^^^^^^^^^^^^^^^^
+
+error[E0271]: type mismatch resolving `<impl DerivedTrait as Trait>::Associated == ()`
+  --> $DIR/issue-87261.rs:82:5
+   |
+LL | fn returns_opaque_derived() -> impl DerivedTrait + 'static {
+   |                                --------------------------- the found opaque type
+...
+LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
+   |                           --------------- required by this bound in `accepts_trait`
+...
+LL |     accepts_trait(returns_opaque_derived());
+   |     ^^^^^^^^^^^^^ expected `()`, found associated type
+   |
+   = note:    expected unit type `()`
+           found associated type `<impl DerivedTrait as Trait>::Associated`
+help: consider constraining the associated type `<impl DerivedTrait as Trait>::Associated` to `()`
+   |
+LL | fn returns_opaque_derived() -> impl DerivedTrait<Associated = ()> + 'static {
+   |                                                 ^^^^^^^^^^^^^^^^^
+
+error[E0271]: type mismatch resolving `<impl Trait+Foo as Trait>::Associated == ()`
+  --> $DIR/issue-87261.rs:85:5
+   |
+LL | fn returns_opaque_foo() -> impl Trait + Foo {
+   |                            ---------------- the found opaque type
+...
+LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
+   |                           --------------- required by this bound in `accepts_trait`
+...
+LL |     accepts_trait(returns_opaque_foo());
+   |     ^^^^^^^^^^^^^ expected `()`, found associated type
+   |
+   = note:    expected unit type `()`
+           found associated type `<impl Trait+Foo as Trait>::Associated`
+help: consider constraining the associated type `<impl Trait+Foo as Trait>::Associated` to `()`
+   |
+LL | fn returns_opaque_foo() -> impl Trait<Associated = ()> + Foo {
+   |                                      ^^^^^^^^^^^^^^^^^
+
+error[E0271]: type mismatch resolving `<impl DerivedTrait+Foo as Trait>::Associated == ()`
+  --> $DIR/issue-87261.rs:88:5
+   |
+LL | fn returns_opaque_derived_foo() -> impl DerivedTrait + Foo {
+   |                                    ----------------------- the found opaque type
+...
+LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
+   |                           --------------- required by this bound in `accepts_trait`
+...
+LL |     accepts_trait(returns_opaque_derived_foo());
+   |     ^^^^^^^^^^^^^ expected `()`, found associated type
+   |
+   = note:    expected unit type `()`
+           found associated type `<impl DerivedTrait+Foo as Trait>::Associated`
+   = help: consider constraining the associated type `<impl DerivedTrait+Foo as Trait>::Associated` to `()`
+   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+
+error[E0271]: type mismatch resolving `<impl GenericTrait<()> as GenericTrait<()>>::Associated == ()`
+  --> $DIR/issue-87261.rs:91:5
+   |
+LL | fn returns_opaque_generic() -> impl GenericTrait<()> + 'static {
+   |                                ------------------------------- the found opaque type
+...
+LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
+   |                                              --------------- required by this bound in `accepts_generic_trait`
+...
+LL |     accepts_generic_trait(returns_opaque_generic());
+   |     ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
+   |
+   = note:    expected unit type `()`
+           found associated type `<impl GenericTrait<()> as GenericTrait<()>>::Associated`
+help: consider constraining the associated type `<impl GenericTrait<()> as GenericTrait<()>>::Associated` to `()`
+   |
+LL | fn returns_opaque_generic() -> impl GenericTrait<(), Associated = ()> + 'static {
+   |                                                    ^^^^^^^^^^^^^^^^^
+
+error[E0271]: type mismatch resolving `<impl GenericTrait<()>+Foo as GenericTrait<()>>::Associated == ()`
+  --> $DIR/issue-87261.rs:94:5
+   |
+LL | fn returns_opaque_generic_foo() -> impl GenericTrait<()> + Foo {
+   |                                    --------------------------- the found opaque type
+...
+LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
+   |                                              --------------- required by this bound in `accepts_generic_trait`
+...
+LL |     accepts_generic_trait(returns_opaque_generic_foo());
+   |     ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
+   |
+   = note:    expected unit type `()`
+           found associated type `<impl GenericTrait<()>+Foo as GenericTrait<()>>::Associated`
+help: consider constraining the associated type `<impl GenericTrait<()>+Foo as GenericTrait<()>>::Associated` to `()`
+   |
+LL | fn returns_opaque_generic_foo() -> impl GenericTrait<(), Associated = ()> + Foo {
+   |                                                        ^^^^^^^^^^^^^^^^^
+
+error[E0271]: type mismatch resolving `<impl GenericTrait<()>+GenericTrait<u8> as GenericTrait<()>>::Associated == ()`
+  --> $DIR/issue-87261.rs:97:5
+   |
+LL | fn returns_opaque_generic_duplicate() -> impl GenericTrait<()> + GenericTrait<u8> {
+   |                                          ---------------------------------------- the found opaque type
+...
+LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
+   |                                              --------------- required by this bound in `accepts_generic_trait`
+...
+LL |     accepts_generic_trait(returns_opaque_generic_duplicate());
+   |     ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
+   |
+   = note:    expected unit type `()`
+           found associated type `<impl GenericTrait<()>+GenericTrait<u8> as GenericTrait<()>>::Associated`
+   = help: consider constraining the associated type `<impl GenericTrait<()>+GenericTrait<u8> as GenericTrait<()>>::Associated` to `()`
+   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+
+error: aborting due to 14 previous errors
+
+For more information about this error, try `rustc --explain E0271`.