diff --git a/libctf/ctf-dedup.c b/libctf/ctf-dedup.c
index 6c58daae324..8bfd839524e 100644
--- a/libctf/ctf-dedup.c
+++ b/libctf/ctf-dedup.c
@@ -2640,7 +2640,7 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
   int input_num = CTF_DEDUP_GID_TO_INPUT (id);
   int output_num = (uint32_t) -1;		/* 'shared' */
   int cu_mapped = *(int *)arg;
-  int isroot = 1;
+  int isroot;
   int is_conflicting;
 
   ctf_next_t *i = NULL;
@@ -2708,9 +2708,11 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
     }
 
   name = ctf_strraw (real_input, tp->ctt_name);
+  isroot = LCTF_INFO_ISROOT (real_input, tp->ctt_info);
 
   /* Hide conflicting types, if we were asked to: also hide if a type with this
-     name already exists and is not a forward.  */
+     name already exists and is not a forward, or if this type is hidden on the
+     input.  */
   if (cu_mapped && is_conflicting)
     isroot = 0;
   else if (name
diff --git a/libctf/testsuite/libctf-writable/ctf-nonroot-linking.c b/libctf/testsuite/libctf-writable/ctf-nonroot-linking.c
new file mode 100644
index 00000000000..6edd189b360
--- /dev/null
+++ b/libctf/testsuite/libctf-writable/ctf-nonroot-linking.c
@@ -0,0 +1,127 @@
+/* Make sure linking a non-root-visible type emits a non-root-visible
+   type, rather than silently promoting it to root-visible.  Do it by dumping,
+   thus also testing the {non-root sigils} you get when dumping
+   non-root-visible types.  */
+
+#include <ctf-api.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+main (int argc, char *argv[])
+{
+  ctf_dict_t *in1;
+  ctf_dict_t *fp;
+  ctf_dict_t *dump_fp;
+  ctf_archive_t *arc1;
+  ctf_archive_t *final_arc;
+  ctf_sect_t s;
+  ctf_encoding_t encoding = { CTF_INT_SIGNED, 0, sizeof (char) };
+  unsigned char *buf1, *buf2;
+  size_t buf1_sz, buf2_sz;
+  ctf_dump_state_t *dump_state = NULL;
+  ctf_next_t *i = NULL;
+  int err;
+
+  /* Linking does not currently work on mingw because of an unreliable tmpfile
+     implementation on that platform (see
+     https://github.com/msys2/MINGW-packages/issues/18878).  Simply skip for
+     now.  */
+
+#ifdef __MINGW32__
+  printf ("UNSUPPORTED: platform bug breaks ctf_link\n");
+  return 0;
+#else
+
+  if ((fp = ctf_create (&err)) == NULL)
+    goto create_err;
+
+  if ((in1 = ctf_create (&err)) == NULL)
+    goto create_err;
+
+  /* A non-root addition. */
+
+  if ((ctf_add_integer (in1, CTF_ADD_NONROOT, "foo", &encoding)) == CTF_ERR)
+    {
+      fprintf (stderr, "Cannot add: %s\n", ctf_errmsg (ctf_errno (in1)));
+      return 1;
+    }
+
+  /* Write it out and read it back in, to turn it into an archive.
+     This would be unnecessary if ctf_link_add() were public :( */
+  if ((buf1 = ctf_write_mem (in1, &buf1_sz, -1)) == NULL)
+    {
+      fprintf (stderr, "Cannot serialize: %s\n", ctf_errmsg (ctf_errno (in1)));
+      return 1;
+    }
+
+  s.cts_name = "foo";
+  s.cts_data = (void *) buf1;
+  s.cts_size = buf1_sz;
+  s.cts_entsize = 64; /* Unimportant.  */
+
+  if ((arc1 = ctf_arc_bufopen (&s, NULL, NULL, &err)) == NULL)
+    goto open_err;
+
+  ctf_dict_close (in1);
+
+  /* Link!  Even a one-file link does deduplication.  */
+
+  if (ctf_link_add_ctf (fp, arc1, "a") < 0)
+    goto link_err;
+
+  if (ctf_link (fp, 0) < 0)
+    goto link_err;
+
+  /* Write it out.  We need a new buf here, because the archive is still
+     using the other buf.  */
+
+  if ((buf2 = ctf_link_write (fp, &buf2_sz, 4096)) == NULL)
+    goto link_err;
+
+  /* Read it back in.  */
+
+  s.cts_data = (void *) buf2;
+  s.cts_size = buf2_sz;
+
+  if ((final_arc = ctf_arc_bufopen (&s, NULL, NULL, &err)) == NULL)
+    goto open_err;
+
+  /* Dump the types, and search for the {sigils of non-rootedness}.  */
+  while ((dump_fp = ctf_archive_next (final_arc, &i, NULL, 0, &err)) != NULL)
+    {
+      char *dumpstr;
+
+      while ((dumpstr = ctf_dump (dump_fp, &dump_state, CTF_SECT_TYPE,
+				  NULL, NULL)) != NULL)
+	{
+	  if (strchr (dumpstr, '{') != NULL && strchr (dumpstr, '}') != NULL)
+	    printf ("Non-root type found.\n");
+	  free (dumpstr);
+	}
+      ctf_dict_close (dump_fp);
+    }
+  if (err != ECTF_NEXT_END)
+    {
+      fprintf (stderr, "Archive iteration error: %s\n", ctf_errmsg (err));
+      return 1;
+    }
+
+  ctf_arc_close (final_arc);
+  free (buf1);
+  free (buf2);
+  ctf_dict_close (fp);
+  return 0;
+
+ create_err:
+  fprintf (stderr, "Cannot create: %s\n", ctf_errmsg (err));
+  return 1;
+ open_err:
+  fprintf (stderr, "Cannot open: %s\n", ctf_errmsg (err));
+  return 1;
+ link_err:
+  fprintf (stderr, "Cannot link: %s\n", ctf_errmsg (ctf_errno (fp)));
+  return 1;
+#endif
+}
diff --git a/libctf/testsuite/libctf-writable/ctf-nonroot-linking.lk b/libctf/testsuite/libctf-writable/ctf-nonroot-linking.lk
new file mode 100644
index 00000000000..e3edda05c5c
--- /dev/null
+++ b/libctf/testsuite/libctf-writable/ctf-nonroot-linking.lk
@@ -0,0 +1 @@
+Non-root type found.
