diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index 81f65ac86900f..981b5bb8ba72f 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -459,6 +459,7 @@ E0773: include_str!("./error_codes/E0773.md"),
 E0774: include_str!("./error_codes/E0774.md"),
 E0775: include_str!("./error_codes/E0775.md"),
 E0776: include_str!("./error_codes/E0776.md"),
+E0777: include_str!("./error_codes/E0777.md"),
 ;
 //  E0006, // merged with E0005
 //  E0008, // cannot bind by-move into a pattern guard
diff --git a/compiler/rustc_error_codes/src/error_codes/E0777.md b/compiler/rustc_error_codes/src/error_codes/E0777.md
new file mode 100644
index 0000000000000..8c5c6e28b65c6
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0777.md
@@ -0,0 +1,19 @@
+A literal value was used inside `#[derive]`.
+
+Erroneous code example:
+
+```compile_fail,E0777
+#[derive("Clone")] // error!
+struct Foo;
+```
+
+Only paths to traits are allowed as argument inside `#[derive]`. You can find
+more information about the `#[derive]` attribute in the [Rust Book].
+
+
+```
+#[derive(Clone)] // ok!
+struct Foo;
+```
+
+[Rust Book]: https://doc.rust-lang.org/book/appendix-03-derivable-traits.html
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index e5cfb866938e5..c6287693dc9e6 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -18,7 +18,7 @@ use rustc_ast_pretty::pprust;
 use rustc_attr::{self as attr, is_builtin_attr, HasAttrs};
 use rustc_data_structures::map_in_place::MapInPlace;
 use rustc_data_structures::stack::ensure_sufficient_stack;
-use rustc_errors::{Applicability, PResult};
+use rustc_errors::{struct_span_err, Applicability, PResult};
 use rustc_feature::Features;
 use rustc_parse::parser::Parser;
 use rustc_parse::validate_attr;
@@ -542,7 +542,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
     fn error_derive_forbidden_on_non_adt(&self, derives: &[Path], item: &Annotatable) {
         let attr = self.cx.sess.find_by_name(item.attrs(), sym::derive);
         let span = attr.map_or(item.span(), |attr| attr.span);
-        let mut err = rustc_errors::struct_span_err!(
+        let mut err = struct_span_err!(
             self.cx.sess,
             span,
             E0774,
diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs
index 94b3fcf2850d2..4c95f19b96dc6 100644
--- a/compiler/rustc_expand/src/proc_macro.rs
+++ b/compiler/rustc_expand/src/proc_macro.rs
@@ -5,7 +5,8 @@ use rustc_ast::token;
 use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_ast::{self as ast, *};
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::{Applicability, ErrorReported};
+use rustc_errors::{struct_span_err, Applicability, ErrorReported};
+use rustc_lexer::is_ident;
 use rustc_parse::nt_to_tokenstream;
 use rustc_span::symbol::sym;
 use rustc_span::{Span, DUMMY_SP};
@@ -182,9 +183,22 @@ crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>)
             .filter_map(|nmi| match nmi {
                 NestedMetaItem::Literal(lit) => {
                     error_reported_filter_map = true;
-                    cx.struct_span_err(lit.span, "expected path to a trait, found literal")
-                        .help("for example, write `#[derive(Debug)]` for `Debug`")
-                        .emit();
+                    let mut err = struct_span_err!(
+                        cx.sess,
+                        lit.span,
+                        E0777,
+                        "expected path to a trait, found literal",
+                    );
+                    let token = lit.token.to_string();
+                    if token.starts_with('"')
+                        && token.len() > 2
+                        && is_ident(&token[1..token.len() - 1])
+                    {
+                        err.help(&format!("try using `#[derive({})]`", &token[1..token.len() - 1]));
+                    } else {
+                        err.help("for example, write `#[derive(Debug)]` for `Debug`");
+                    }
+                    err.emit();
                     None
                 }
                 NestedMetaItem::MetaItem(mi) => Some(mi),
diff --git a/src/test/ui/error-codes/E0777.rs b/src/test/ui/error-codes/E0777.rs
new file mode 100644
index 0000000000000..ff70f73686665
--- /dev/null
+++ b/src/test/ui/error-codes/E0777.rs
@@ -0,0 +1,7 @@
+#[derive("Clone")] //~ ERROR E0777
+#[derive("Clone
+")]
+//~^^ ERROR E0777
+struct Foo;
+
+fn main() {}
diff --git a/src/test/ui/error-codes/E0777.stderr b/src/test/ui/error-codes/E0777.stderr
new file mode 100644
index 0000000000000..ea73c58993e2b
--- /dev/null
+++ b/src/test/ui/error-codes/E0777.stderr
@@ -0,0 +1,21 @@
+error[E0777]: expected path to a trait, found literal
+  --> $DIR/E0777.rs:1:10
+   |
+LL | #[derive("Clone")]
+   |          ^^^^^^^
+   |
+   = help: try using `#[derive(Clone)]`
+
+error[E0777]: expected path to a trait, found literal
+  --> $DIR/E0777.rs:2:10
+   |
+LL |   #[derive("Clone
+   |  __________^
+LL | | ")]
+   | |_^
+   |
+   = help: for example, write `#[derive(Debug)]` for `Debug`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0777`.