diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
index 30ac1d47af..a041f84ec0 100644
--- a/common/CMakeLists.txt
+++ b/common/CMakeLists.txt
@@ -378,7 +378,6 @@ set( PLOTTERS_CONTROL_SRCS
     )
 
 set( COMMON_IO_SRCS
-    io/plugin_file_desc.cpp
     io/io_base.cpp
     io/io_utils.cpp
 
diff --git a/common/io/io_base.cpp b/common/io/io_base.cpp
index e0be02a158..030ce1bee9 100644
--- a/common/io/io_base.cpp
+++ b/common/io/io_base.cpp
@@ -20,6 +20,8 @@
 
 #include <io/io_base.h>
 #include <ki_exception.h>
+#include <wildcards_and_files_ext.h>
+#include <wx/translation.h>
 
 #define FMT_UNIMPLEMENTED wxT( "IO interface \"%s\" does not implement the \"%s\" function." )
 #define NOT_IMPLEMENTED( aCaller )                                       \
@@ -28,6 +30,12 @@
                                       wxString::FromUTF8( aCaller ) ) );
 
 
+wxString IO_BASE::IO_FILE_DESC::FileFilter() const
+{
+    return wxGetTranslation( m_Description ) + AddFileExtListToFilter( m_FileExtensions );
+}
+
+
 void IO_BASE::CreateLibrary( const wxString& aLibraryPath, const STRING_UTF8_MAP* aProperties )
 {
     NOT_IMPLEMENTED( __FUNCTION__ );
diff --git a/common/io/plugin_file_desc.cpp b/common/io/plugin_file_desc.cpp
deleted file mode 100644
index de6c84e408..0000000000
--- a/common/io/plugin_file_desc.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * This program source code file is part of KiCad, a free EDA CAD application.
- *
- * Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, you may find one here:
- * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
- * or you may search the http://www.gnu.org website for the version 2 license,
- * or you may write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
- */
-
-#include <plugin_file_desc.h>
-#include <wildcards_and_files_ext.h>
-#include <wx/translation.h>
-
-
-wxString PLUGIN_FILE_DESC::FileFilter() const
-{
-    return wxGetTranslation( m_Description ) + AddFileExtListToFilter( m_FileExtensions );
-}
\ No newline at end of file
diff --git a/eeschema/dialogs/panel_sym_lib_table.cpp b/eeschema/dialogs/panel_sym_lib_table.cpp
index ca622db000..2e2639d2c4 100644
--- a/eeschema/dialogs/panel_sym_lib_table.cpp
+++ b/eeschema/dialogs/panel_sym_lib_table.cpp
@@ -261,7 +261,7 @@ PANEL_SYM_LIB_TABLE::PANEL_SYM_LIB_TABLE( DIALOG_EDIT_LIBRARY_TABLES* aParent, P
         if( !pi )
             continue;
 
-        if( PLUGIN_FILE_DESC desc = pi->GetLibraryFileDesc() )
+        if( const IO_BASE::IO_FILE_DESC& desc = pi->GetLibraryDesc() )
             pluginChoices.Add( SCH_IO_MGR::ShowType( type ) );
     }
 
@@ -312,7 +312,7 @@ PANEL_SYM_LIB_TABLE::PANEL_SYM_LIB_TABLE( DIALOG_EDIT_LIBRARY_TABLES* aParent, P
 
                             if( pi )
                             {
-                                const PLUGIN_FILE_DESC& desc = pi->GetLibraryFileDesc();
+                                const IO_BASE::IO_FILE_DESC& desc = pi->GetLibraryDesc();
 
                                 if( desc.m_IsFile )
                                     return desc.FileFilter();
@@ -590,7 +590,7 @@ void PANEL_SYM_LIB_TABLE::browseLibrariesHandler( wxCommandEvent& event )
         if( !pi )
             continue;
 
-        const PLUGIN_FILE_DESC& desc = pi->GetLibraryFileDesc();
+        const IO_BASE::IO_FILE_DESC& desc = pi->GetLibraryDesc();
 
         if( desc.m_FileExtensions.empty() )
             continue;
diff --git a/eeschema/files-io.cpp b/eeschema/files-io.cpp
index 8f3b276a4f..6d829dbe14 100644
--- a/eeschema/files-io.cpp
+++ b/eeschema/files-io.cpp
@@ -674,7 +674,7 @@ void SCH_EDIT_FRAME::OnImportProject( wxCommandEvent& aEvent )
         if( !pi )
             continue;
 
-        const PLUGIN_FILE_DESC& desc = pi->GetSchematicFileDesc();
+        const IO_BASE::IO_FILE_DESC& desc = pi->GetSchematicFileDesc();
 
         if( desc.m_FileExtensions.empty() )
             continue;
diff --git a/eeschema/sch_io/altium/sch_io_altium.h b/eeschema/sch_io/altium/sch_io_altium.h
index 1c546684a7..cbfc5cedd9 100644
--- a/eeschema/sch_io/altium/sch_io_altium.h
+++ b/eeschema/sch_io/altium/sch_io_altium.h
@@ -58,15 +58,15 @@ public:
     SCH_IO_ALTIUM();
     ~SCH_IO_ALTIUM();
 
-    const PLUGIN_FILE_DESC GetSchematicFileDesc() const override
+    const IO_BASE::IO_FILE_DESC GetSchematicFileDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "Altium schematic files" ), { "SchDoc" } );
+        return IO_BASE::IO_FILE_DESC( _HKI( "Altium schematic files" ), { "SchDoc" } );
     }
 
-    const PLUGIN_FILE_DESC GetLibraryFileDesc() const override
+    const IO_BASE::IO_FILE_DESC GetLibraryDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "Altium Schematic Library or Integrated Library" ),
-                                 { "SchLib", "IntLib" } );
+        return IO_BASE::IO_FILE_DESC( _HKI( "Altium Schematic Library or Integrated Library" ),
+                                      { "SchLib", "IntLib" } );
     }
 
     bool CanReadSchematicFile( const wxString& aFileName ) const override;
diff --git a/eeschema/sch_io/cadstar/sch_io_cadstar_archive.h b/eeschema/sch_io/cadstar/sch_io_cadstar_archive.h
index 8716f579cf..dae0cdf37d 100644
--- a/eeschema/sch_io/cadstar/sch_io_cadstar_archive.h
+++ b/eeschema/sch_io/cadstar/sch_io_cadstar_archive.h
@@ -50,16 +50,16 @@ public:
         m_progressReporter = aReporter;
     }
 
-    const PLUGIN_FILE_DESC GetSchematicFileDesc() const override
+    const IO_BASE::IO_FILE_DESC GetSchematicFileDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "CADSTAR Schematic Archive files" ),
-                                 { CadstarSchematicFileExtension } );
+        return IO_BASE::IO_FILE_DESC( _HKI( "CADSTAR Schematic Archive files" ),
+                                      { CadstarSchematicFileExtension } );
     }
 
-    const PLUGIN_FILE_DESC GetLibraryFileDesc() const override
+    const IO_BASE::IO_FILE_DESC GetLibraryDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "CADSTAR Parts Library files" ),
-                                 { CadstarPartsLibraryFileExtension } );
+        return IO_BASE::IO_FILE_DESC( _HKI( "CADSTAR Parts Library files" ),
+                                      { CadstarPartsLibraryFileExtension } );
     }
 
     bool CanReadLibrary( const wxString& aFileName ) const override;
diff --git a/eeschema/sch_io/database/sch_io_database.h b/eeschema/sch_io/database/sch_io_database.h
index 75903fae34..943d4a94d3 100644
--- a/eeschema/sch_io/database/sch_io_database.h
+++ b/eeschema/sch_io/database/sch_io_database.h
@@ -45,10 +45,10 @@ public:
     SCH_IO_DATABASE();
     virtual ~SCH_IO_DATABASE();
 
-    const PLUGIN_FILE_DESC GetLibraryFileDesc() const override
+    const IO_BASE::IO_FILE_DESC GetLibraryDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "KiCad database library files" ),
-                                 { DatabaseLibraryFileExtension } );
+        return IO_BASE::IO_FILE_DESC( _HKI( "KiCad database library files" ),
+                                      { DatabaseLibraryFileExtension } );
     }
 
     int GetModifyHash() const override { return 0; }
diff --git a/eeschema/sch_io/eagle/sch_io_eagle.h b/eeschema/sch_io/eagle/sch_io_eagle.h
index a25c8dd6f5..01de580ce4 100644
--- a/eeschema/sch_io/eagle/sch_io_eagle.h
+++ b/eeschema/sch_io/eagle/sch_io_eagle.h
@@ -86,14 +86,14 @@ public:
     SCH_IO_EAGLE();
     ~SCH_IO_EAGLE();
 
-    const PLUGIN_FILE_DESC GetSchematicFileDesc() const override
+    const IO_BASE::IO_FILE_DESC GetSchematicFileDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "Eagle XML schematic files" ), { "sch" } );
+        return IO_BASE::IO_FILE_DESC( _HKI( "Eagle XML schematic files" ), { "sch" } );
     }
 
-    const PLUGIN_FILE_DESC GetLibraryFileDesc() const override
+    const IO_BASE::IO_FILE_DESC GetLibraryDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "Eagle XML library files" ), { "lbr" } );
+        return IO_BASE::IO_FILE_DESC( _HKI( "Eagle XML library files" ), { "lbr" } );
     }
 
     bool CanReadSchematicFile( const wxString& aFileName ) const override;
diff --git a/eeschema/sch_io/easyeda/sch_io_easyeda.h b/eeschema/sch_io/easyeda/sch_io_easyeda.h
index ccd31c8f84..8c2fbc263a 100644
--- a/eeschema/sch_io/easyeda/sch_io_easyeda.h
+++ b/eeschema/sch_io/easyeda/sch_io_easyeda.h
@@ -45,12 +45,12 @@ public:
 
     ~SCH_IO_EASYEDA() {}
 
-    const PLUGIN_FILE_DESC GetSchematicFileDesc() const override
+    const IO_BASE::IO_FILE_DESC GetSchematicFileDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "EasyEDA (JLCEDA) Std files" ), { "json" } );
+        return IO_BASE::IO_FILE_DESC( _HKI( "EasyEDA (JLCEDA) Std files" ), { "json" } );
     }
 
-    const PLUGIN_FILE_DESC GetLibraryFileDesc() const override { return GetSchematicFileDesc(); }
+    const IO_BASE::IO_FILE_DESC GetLibraryDesc() const override { return GetSchematicFileDesc(); }
 
     bool CanReadSchematicFile( const wxString& aFileName ) const override;
 
diff --git a/eeschema/sch_io/easyedapro/sch_io_easyedapro.h b/eeschema/sch_io/easyedapro/sch_io_easyedapro.h
index 096a9a2a39..c8e2a57d86 100644
--- a/eeschema/sch_io/easyedapro/sch_io_easyedapro.h
+++ b/eeschema/sch_io/easyedapro/sch_io_easyedapro.h
@@ -41,14 +41,14 @@ public:
     SCH_IO_EASYEDAPRO();
     ~SCH_IO_EASYEDAPRO();
 
-    const PLUGIN_FILE_DESC GetSchematicFileDesc() const override
+    const IO_BASE::IO_FILE_DESC GetSchematicFileDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "EasyEDA (JLCEDA) Pro files" ), { "epro", "zip" } );
+        return IO_BASE::IO_FILE_DESC( _HKI( "EasyEDA (JLCEDA) Pro files" ), { "epro", "zip" } );
     }
 
-    const PLUGIN_FILE_DESC GetLibraryFileDesc() const override
+    const IO_BASE::IO_FILE_DESC GetLibraryDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "EasyEDA (JLCEDA) Pro files" ), { "elibz", "epro", "zip" } );
+        return IO_BASE::IO_FILE_DESC( _HKI( "EasyEDA (JLCEDA) Pro files" ), { "elibz", "epro", "zip" } );
     }
 
     bool CanReadSchematicFile( const wxString& aFileName ) const override;
diff --git a/eeschema/sch_io/http_lib/sch_io_http_lib.h b/eeschema/sch_io/http_lib/sch_io_http_lib.h
index c143fb6d37..87125a6358 100644
--- a/eeschema/sch_io/http_lib/sch_io_http_lib.h
+++ b/eeschema/sch_io/http_lib/sch_io_http_lib.h
@@ -42,10 +42,10 @@ public:
     SCH_IO_HTTP_LIB();
     virtual ~SCH_IO_HTTP_LIB();
 
-    const PLUGIN_FILE_DESC GetLibraryFileDesc() const override
+    const IO_BASE::IO_FILE_DESC GetLibraryDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "KiCad HTTP library files" ),
-            { HTTPLibraryFileExtension } );
+        return IO_BASE::IO_FILE_DESC( _HKI( "KiCad HTTP library files" ),
+                                      { HTTPLibraryFileExtension } );
     }
 
     int GetModifyHash() const override { return 0; }
diff --git a/eeschema/sch_io/kicad_legacy/sch_io_kicad_legacy.h b/eeschema/sch_io/kicad_legacy/sch_io_kicad_legacy.h
index fa38970958..c54c3e1780 100644
--- a/eeschema/sch_io/kicad_legacy/sch_io_kicad_legacy.h
+++ b/eeschema/sch_io/kicad_legacy/sch_io_kicad_legacy.h
@@ -70,16 +70,16 @@ public:
     SCH_IO_KICAD_LEGACY();
     virtual ~SCH_IO_KICAD_LEGACY();
 
-    const PLUGIN_FILE_DESC GetSchematicFileDesc() const override
+    const IO_BASE::IO_FILE_DESC GetSchematicFileDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "KiCad legacy schematic files" ),
-                                 { LegacySchematicFileExtension } );
+        return IO_BASE::IO_FILE_DESC( _HKI( "KiCad legacy schematic files" ),
+                                      { LegacySchematicFileExtension } );
     }
 
-    const PLUGIN_FILE_DESC GetLibraryFileDesc() const override
+    const IO_BASE::IO_FILE_DESC GetLibraryDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "KiCad legacy symbol library files" ),
-                                 { LegacySymbolLibFileExtension } );
+        return IO_BASE::IO_FILE_DESC( _HKI( "KiCad legacy symbol library files" ),
+                                      { LegacySymbolLibFileExtension } );
     }
 
     bool CanReadSchematicFile( const wxString& aFileName ) const override;
diff --git a/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr.h b/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr.h
index 26817fe0f8..34f71e1c6e 100644
--- a/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr.h
+++ b/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr.h
@@ -69,16 +69,16 @@ public:
     SCH_IO_KICAD_SEXPR();
     virtual ~SCH_IO_KICAD_SEXPR();
 
-    const PLUGIN_FILE_DESC GetSchematicFileDesc() const override
+    const IO_BASE::IO_FILE_DESC GetSchematicFileDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "KiCad s-expression schematic files" ),
-                                 { KiCadSchematicFileExtension } );
+        return IO_BASE::IO_FILE_DESC( _HKI( "KiCad s-expression schematic files" ),
+                                      { KiCadSchematicFileExtension } );
     }
 
-    const PLUGIN_FILE_DESC GetLibraryFileDesc() const override
+    const IO_BASE::IO_FILE_DESC GetLibraryDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "KiCad symbol library files" ),
-                                 { KiCadSymbolLibFileExtension } );
+        return IO_BASE::IO_FILE_DESC( _HKI( "KiCad symbol library files" ),
+                                      { KiCadSymbolLibFileExtension } );
     }
 
     /**
diff --git a/eeschema/sch_io/ltspice/sch_io_ltspice.h b/eeschema/sch_io/ltspice/sch_io_ltspice.h
index 379a942a33..896baea758 100644
--- a/eeschema/sch_io/ltspice/sch_io_ltspice.h
+++ b/eeschema/sch_io/ltspice/sch_io_ltspice.h
@@ -44,15 +44,17 @@ public:
     {
     }
 
-    const PLUGIN_FILE_DESC GetSchematicFileDesc() const override
+    const IO_BASE::IO_FILE_DESC GetSchematicFileDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "LTspice schematic files" ), { "asc" } );
+        return IO_BASE::IO_FILE_DESC( _HKI( "LTspice schematic files" ), { "asc" } );
     }
 
-    /*const PLUGIN_FILE_DESC GetLibraryFileDesc() const override
+    const IO_BASE::IO_FILE_DESC GetLibraryDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "LTspice library files" ), { "lib" } );
-    }*/
+        // This was originally commented out, so keep it commented and just return an empty library description
+        //return IO_BASE::IO_FILE_DESC( _HKI( "LTspice library files" ), { "lib" } );
+        return IO_BASE::IO_FILE_DESC( wxEmptyString, { } );
+    }
 
     int GetModifyHash() const override;
 
diff --git a/eeschema/sch_io/sch_io.cpp b/eeschema/sch_io/sch_io.cpp
index af905f36eb..c9faff6f50 100644
--- a/eeschema/sch_io/sch_io.cpp
+++ b/eeschema/sch_io/sch_io.cpp
@@ -37,15 +37,9 @@
                                       wxString::FromUTF8( aCaller ).GetData() ) );
 
 
-const PLUGIN_FILE_DESC SCH_IO::GetSchematicFileDesc() const
+const IO_BASE::IO_FILE_DESC SCH_IO::GetSchematicFileDesc() const
 {
-    return PLUGIN_FILE_DESC( wxEmptyString, {} );
-}
-
-
-const PLUGIN_FILE_DESC SCH_IO::GetLibraryFileDesc() const
-{
-    return PLUGIN_FILE_DESC( wxEmptyString, {} );
+    return IO_BASE::IO_FILE_DESC( wxEmptyString, {} );
 }
 
 
@@ -67,7 +61,7 @@ bool SCH_IO::CanReadSchematicFile( const wxString& aFileName ) const
 
 bool SCH_IO::CanReadLibrary( const wxString& aFileName ) const
 {
-    const PLUGIN_FILE_DESC& desc = GetLibraryFileDesc();
+    const IO_BASE::IO_FILE_DESC& desc = GetLibraryFileDesc();
 
     if( desc.m_IsFile )
     {
diff --git a/eeschema/sch_io/sch_io.h b/eeschema/sch_io/sch_io.h
index f2dbd4c001..00105ae877 100644
--- a/eeschema/sch_io/sch_io.h
+++ b/eeschema/sch_io/sch_io.h
@@ -30,7 +30,6 @@
 #include <enum_vector.h>
 #include <reporter.h>
 #include <i18n_utility.h>
-#include <plugin_file_desc.h>
 #include <wx/arrstr.h>
 
 /**
@@ -63,12 +62,7 @@ public:
     /**
      * Returns schematic file description for the #SCH_IO.
      */
-    virtual const PLUGIN_FILE_DESC GetSchematicFileDesc() const;
-
-    /**
-     * Returns symbol library description for the #SCH_IO.
-     */
-    virtual const PLUGIN_FILE_DESC GetLibraryFileDesc() const;
+    virtual const IO_BASE::IO_FILE_DESC GetSchematicFileDesc() const;
 
     /**
      * Checks if this SCH_IO can read the specified schematic file.
diff --git a/eeschema/sch_io/sch_io_mgr.h b/eeschema/sch_io/sch_io_mgr.h
index 262b360da9..2aeecc8361 100644
--- a/eeschema/sch_io/sch_io_mgr.h
+++ b/eeschema/sch_io/sch_io_mgr.h
@@ -28,7 +28,7 @@
 #include <enum_vector.h>
 #include <reporter.h>
 #include <i18n_utility.h>
-#include <plugin_file_desc.h>
+#include <io/io_base.h>
 #include <wx/arrstr.h>
 
 
diff --git a/eeschema/symbol_editor/symbol_editor_import_export.cpp b/eeschema/symbol_editor/symbol_editor_import_export.cpp
index 01f99470d9..c35ad9e855 100644
--- a/eeschema/symbol_editor/symbol_editor_import_export.cpp
+++ b/eeschema/symbol_editor/symbol_editor_import_export.cpp
@@ -61,7 +61,7 @@ void SYMBOL_EDIT_FRAME::ImportSymbol()
         if( !pi )
             continue;
 
-        const PLUGIN_FILE_DESC& desc = pi->GetLibraryFileDesc();
+        const IO_BASE::IO_FILE_DESC& desc = pi->GetLibraryFileDesc();
 
         if( desc.m_FileExtensions.empty() )
             continue;
diff --git a/include/io/io_base.h b/include/io/io_base.h
index 69efc11f76..0263ceb677 100644
--- a/include/io/io_base.h
+++ b/include/io/io_base.h
@@ -21,6 +21,8 @@
 #ifndef IO_BASE_H_
 #define IO_BASE_H_
 
+#include <vector>
+#include <string>
 #include <wx/string.h>
 
 class REPORTER;
@@ -30,6 +32,33 @@ class STRING_UTF8_MAP;
 class IO_BASE
 {
 public:
+    /**
+    * Container that describes file type info
+    */
+    struct IO_FILE_DESC
+    {
+        wxString                 m_Description;    ///< Description shown in the file picker dialog
+        std::vector<std::string> m_FileExtensions; ///< Filter used for file pickers if m_IsFile is true
+        std::vector<std::string> m_ExtensionsInDir; ///< In case of folders: extensions of files inside
+        bool                     m_IsFile;          ///< Whether the library is a folder or a file
+
+        IO_FILE_DESC( const wxString& aDescription, const std::vector<std::string>& aFileExtensions,
+                      const std::vector<std::string>& aExtsInFolder = {}, bool aIsFile = true ) :
+                m_Description( aDescription ),
+                m_FileExtensions( aFileExtensions ), m_ExtensionsInDir( aExtsInFolder ),
+                m_IsFile( aIsFile )
+        {
+        }
+
+        IO_FILE_DESC() : IO_FILE_DESC( wxEmptyString, {} ) {}
+
+        /**
+         * @return translated description + wildcards string for file dialogs.
+         */
+        wxString FileFilter() const;
+
+        operator bool() const { return !m_Description.empty(); }
+    };
 
     virtual ~IO_BASE() = default;
 
@@ -53,6 +82,22 @@ public:
     // Library-related functions
     ////////////////////////////////////////////////////
 
+    /**
+     * Get the descriptor for the library container that this IO plugin operates on.
+     *
+     * @return File descriptor for the container of the library elements
+     */
+    virtual const IO_FILE_DESC GetLibraryDesc() const = 0;
+
+    /**
+     * Get the descriptor for the individual library elements that this IO plugin operates on.
+     * For libraries where all the elements are in a single container (e.g. all elements in a single file),
+     * then this will return the descriptor from #IO_BASE::GetLibraryDesc().
+     *
+     * @return File descriptor for the library elements
+     */
+    virtual const IO_FILE_DESC GetLibraryFileDesc() const { return GetLibraryDesc(); }
+
     /**
      * Checks if this IO object can read the specified library file/directory.
      * If not overriden, extension check is used.
diff --git a/include/plugin_file_desc.h b/include/plugin_file_desc.h
deleted file mode 100644
index 9dbc78ef82..0000000000
--- a/include/plugin_file_desc.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * This program source code file is part of KiCad, a free EDA CAD application.
- *
- * Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, you may find one here:
- * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
- * or you may search the http://www.gnu.org website for the version 2 license,
- * or you may write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
- */
-
-#ifndef PLUGIN_FILE_DESC_H_
-#define PLUGIN_FILE_DESC_H_
-
-#include <vector>
-#include <string>
-#include <wx/string.h>
-
-/**
-* Container that describes file type info
-*/
-struct PLUGIN_FILE_DESC
-{
-    wxString                 m_Description;    ///< Description shown in the file picker dialog
-    std::vector<std::string> m_FileExtensions; ///< Filter used for file pickers if m_IsFile is true
-    std::vector<std::string> m_ExtensionsInDir; ///< In case of folders: extensions of files inside
-    bool                     m_IsFile;          ///< Whether the library is a folder or a file
-
-    PLUGIN_FILE_DESC( const wxString& aDescription, const std::vector<std::string>& aFileExtensions,
-                      const std::vector<std::string>& aExtsInFolder = {}, bool aIsFile = true ) :
-            m_Description( aDescription ),
-            m_FileExtensions( aFileExtensions ), m_ExtensionsInDir( aExtsInFolder ),
-            m_IsFile( aIsFile )
-    {
-    }
-
-    PLUGIN_FILE_DESC() : PLUGIN_FILE_DESC( wxEmptyString, {} ) {}
-
-    /**
-     * @return translated description + wildcards string for file dialogs.
-     */
-    wxString FileFilter() const;
-
-    operator bool() const { return !m_Description.empty(); }
-};
-
-#endif // PLUGIN_FILE_DESC_H_
\ No newline at end of file
diff --git a/pcbnew/dialogs/panel_fp_lib_table.cpp b/pcbnew/dialogs/panel_fp_lib_table.cpp
index 4e27685392..caaf17eae5 100644
--- a/pcbnew/dialogs/panel_fp_lib_table.cpp
+++ b/pcbnew/dialogs/panel_fp_lib_table.cpp
@@ -365,7 +365,7 @@ PANEL_FP_LIB_TABLE::PANEL_FP_LIB_TABLE( DIALOG_EDIT_LIBRARY_TABLES* aParent, PRO
                             auto* libTable = static_cast<FP_LIB_TABLE_GRID*>( grid->GetTable() );
                             auto* tableRow = static_cast<FP_LIB_TABLE_ROW*>( libTable->at( row ) );
                             PCB_IO_MGR::PCB_FILE_T fileType = tableRow->GetFileType();
-                            const PLUGIN_FILE_DESC& pluginDesc = m_supportedFpFiles.at( fileType );
+                            const IO_BASE::IO_FILE_DESC& pluginDesc = m_supportedFpFiles.at( fileType );
 
                             if( pluginDesc.m_IsFile )
                                 return pluginDesc.FileFilter();
@@ -519,7 +519,7 @@ void PANEL_FP_LIB_TABLE::populatePluginList()
         if( !pi )
             continue;
 
-        if( PLUGIN_FILE_DESC desc = pi->GetFootprintLibDesc() )
+        if( const IO_BASE::IO_FILE_DESC& desc = pi->GetLibraryDesc() )
             m_supportedFpFiles.emplace( plugin.m_type, desc );
     }
 }
@@ -954,7 +954,7 @@ void PANEL_FP_LIB_TABLE::browseLibrariesHandler( wxCommandEvent& event )
         return;
     }
 
-    const PLUGIN_FILE_DESC& fileDesc = m_supportedFpFiles.at( fileType );
+    const IO_BASE::IO_FILE_DESC& fileDesc = m_supportedFpFiles.at( fileType );
     PCBNEW_SETTINGS*        cfg = Pgm().GetSettingsManager().GetAppSettings<PCBNEW_SETTINGS>();
 
     wxString title = wxString::Format( _( "Select %s Library" ), PCB_IO_MGR::ShowType( fileType ) );
diff --git a/pcbnew/dialogs/panel_fp_lib_table.h b/pcbnew/dialogs/panel_fp_lib_table.h
index 667894b8af..998a8098df 100644
--- a/pcbnew/dialogs/panel_fp_lib_table.h
+++ b/pcbnew/dialogs/panel_fp_lib_table.h
@@ -100,7 +100,7 @@ private:
     //< Transient (unsaved) last browsed folder when adding a project level library.
     wxString         m_lastProjectLibDir;
 
-    std::map<PCB_IO_MGR::PCB_FILE_T, PLUGIN_FILE_DESC> m_supportedFpFiles;
+    std::map<PCB_IO_MGR::PCB_FILE_T, IO_BASE::IO_FILE_DESC> m_supportedFpFiles;
 };
 
 #endif    // PANEL_FP_LIB_TABLE_H
diff --git a/pcbnew/files.cpp b/pcbnew/files.cpp
index d9f3b86ac0..1c2d11c470 100644
--- a/pcbnew/files.cpp
+++ b/pcbnew/files.cpp
@@ -95,7 +95,7 @@
  */
 bool AskLoadBoardFileName( PCB_EDIT_FRAME* aParent, wxString* aFileName, int aCtl = 0 )
 {
-    std::vector<PLUGIN_FILE_DESC> descriptions;
+    std::vector<IO_BASE::IO_FILE_DESC> descriptions;
 
     for( const auto& plugin : PCB_IO_MGR::PLUGIN_REGISTRY::Instance()->AllPlugins() )
     {
@@ -111,7 +111,7 @@ bool AskLoadBoardFileName( PCB_EDIT_FRAME* aParent, wxString* aFileName, int aCt
         PCB_IO::RELEASER pi( plugin.m_createFunc() );
         wxCHECK( pi, false );
 
-        const PLUGIN_FILE_DESC& desc = pi->GetBoardFileDesc();
+        const IO_BASE::IO_FILE_DESC& desc = pi->GetBoardFileDesc();
 
         if( desc.m_FileExtensions.empty() )
             continue;
@@ -123,7 +123,7 @@ bool AskLoadBoardFileName( PCB_EDIT_FRAME* aParent, wxString* aFileName, int aCt
     std::vector<std::string> allExtensions;
     std::set<wxString>       allWildcardsSet;
 
-    for( const PLUGIN_FILE_DESC& desc : descriptions )
+    for( const IO_BASE::IO_FILE_DESC& desc : descriptions )
     {
         if( !fileFiltersStr.IsEmpty() )
             fileFiltersStr += wxChar( '|' );
diff --git a/pcbnew/footprint_libraries_utils.cpp b/pcbnew/footprint_libraries_utils.cpp
index b71e555b1b..de5badca70 100644
--- a/pcbnew/footprint_libraries_utils.cpp
+++ b/pcbnew/footprint_libraries_utils.cpp
@@ -95,7 +95,7 @@ FOOTPRINT* FOOTPRINT_EDIT_FRAME::ImportFootprint( const wxString& aName )
             if( !pi )
                 continue;
 
-            PLUGIN_FILE_DESC desc = pi->GetFootprintFileDesc();
+            const IO_BASE::IO_FILE_DESC& desc = pi->GetLibraryFileDesc();
 
             if( !desc )
                 continue;
@@ -153,7 +153,7 @@ FOOTPRINT* FOOTPRINT_EDIT_FRAME::ImportFootprint( const wxString& aName )
         if( !pi )
             continue;
 
-        if( pi->GetFootprintFileDesc().m_FileExtensions.empty() )
+        if( pi->GetLibraryFileDesc().m_FileExtensions.empty() )
             continue;
 
         if( pi->CanReadFootprint( fn.GetFullPath() ) )
diff --git a/pcbnew/pcb_io/altium/pcb_io_altium_circuit_maker.cpp b/pcbnew/pcb_io/altium/pcb_io_altium_circuit_maker.cpp
index 70d5a8bac9..2090bb24a2 100644
--- a/pcbnew/pcb_io/altium/pcb_io_altium_circuit_maker.cpp
+++ b/pcbnew/pcb_io/altium/pcb_io_altium_circuit_maker.cpp
@@ -49,12 +49,6 @@ PCB_IO_ALTIUM_CIRCUIT_MAKER::~PCB_IO_ALTIUM_CIRCUIT_MAKER()
 }
 
 
-PLUGIN_FILE_DESC PCB_IO_ALTIUM_CIRCUIT_MAKER::GetBoardFileDesc() const
-{
-    return PLUGIN_FILE_DESC( _HKI( "Altium Circuit Maker PCB files" ), { "CMPcbDoc" } );
-}
-
-
 bool PCB_IO_ALTIUM_CIRCUIT_MAKER::CanReadBoard( const wxString& aFileName ) const
 {
     if( !PCB_IO::CanReadBoard( aFileName ) )
diff --git a/pcbnew/pcb_io/altium/pcb_io_altium_circuit_maker.h b/pcbnew/pcb_io/altium/pcb_io_altium_circuit_maker.h
index ddc771e7da..e610c7e9a3 100644
--- a/pcbnew/pcb_io/altium/pcb_io_altium_circuit_maker.h
+++ b/pcbnew/pcb_io/altium/pcb_io_altium_circuit_maker.h
@@ -32,7 +32,16 @@
 class PCB_IO_ALTIUM_CIRCUIT_MAKER : public PCB_IO
 {
 public:
-    PLUGIN_FILE_DESC GetBoardFileDesc() const override;
+    const IO_BASE::IO_FILE_DESC GetBoardFileDesc() const override
+    {
+        return IO_BASE::IO_FILE_DESC( _HKI( "Altium Circuit Maker PCB files" ), { "CMPcbDoc" } );
+    }
+
+    const IO_BASE::IO_FILE_DESC GetLibraryDesc() const override
+    {
+        // No library description for this plugin
+        return IO_BASE::IO_FILE_DESC( wxEmptyString, {} );
+    }
 
     bool CanReadBoard( const wxString& aFileName ) const override;
 
diff --git a/pcbnew/pcb_io/altium/pcb_io_altium_circuit_studio.cpp b/pcbnew/pcb_io/altium/pcb_io_altium_circuit_studio.cpp
index c89765de2f..b9e0754c7f 100644
--- a/pcbnew/pcb_io/altium/pcb_io_altium_circuit_studio.cpp
+++ b/pcbnew/pcb_io/altium/pcb_io_altium_circuit_studio.cpp
@@ -49,12 +49,6 @@ PCB_IO_ALTIUM_CIRCUIT_STUDIO::~PCB_IO_ALTIUM_CIRCUIT_STUDIO()
 }
 
 
-PLUGIN_FILE_DESC PCB_IO_ALTIUM_CIRCUIT_STUDIO::GetBoardFileDesc() const
-{
-    return PLUGIN_FILE_DESC( _HKI( "Altium Circuit Studio PCB files" ), { "CSPcbDoc" } );
-}
-
-
 bool PCB_IO_ALTIUM_CIRCUIT_STUDIO::CanReadBoard( const wxString& aFileName ) const
 {
     if( !PCB_IO::CanReadBoard( aFileName ) )
diff --git a/pcbnew/pcb_io/altium/pcb_io_altium_circuit_studio.h b/pcbnew/pcb_io/altium/pcb_io_altium_circuit_studio.h
index 02993acf08..2e136f5085 100644
--- a/pcbnew/pcb_io/altium/pcb_io_altium_circuit_studio.h
+++ b/pcbnew/pcb_io/altium/pcb_io_altium_circuit_studio.h
@@ -31,7 +31,16 @@
 class PCB_IO_ALTIUM_CIRCUIT_STUDIO : public PCB_IO
 {
 public:
-    PLUGIN_FILE_DESC GetBoardFileDesc() const override;
+    const IO_BASE::IO_FILE_DESC GetBoardFileDesc() const override
+    {
+        return IO_BASE::IO_FILE_DESC( _HKI( "Altium Circuit Studio PCB files" ), { "CSPcbDoc" } );
+    }
+
+    const IO_BASE::IO_FILE_DESC GetLibraryDesc() const override
+    {
+        // No library description for this plugin
+        return IO_BASE::IO_FILE_DESC( wxEmptyString, {} );
+    }
 
     bool CanReadBoard( const wxString& aFileName ) const override;
 
diff --git a/pcbnew/pcb_io/altium/pcb_io_altium_designer.h b/pcbnew/pcb_io/altium/pcb_io_altium_designer.h
index 91b455bce0..bb9bfa601f 100644
--- a/pcbnew/pcb_io/altium/pcb_io_altium_designer.h
+++ b/pcbnew/pcb_io/altium/pcb_io_altium_designer.h
@@ -37,19 +37,17 @@ class PCB_IO_ALTIUM_DESIGNER : public PCB_IO
 {
 public:
     // -----<PUBLIC PCB_IO API>--------------------------------------------------
-    PLUGIN_FILE_DESC GetBoardFileDesc() const override
+    const IO_BASE::IO_FILE_DESC GetBoardFileDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "Altium Designer PCB files" ), { "PcbDoc" } );
+        return IO_BASE::IO_FILE_DESC( _HKI( "Altium Designer PCB files" ), { "PcbDoc" } );
     }
 
-    PLUGIN_FILE_DESC GetFootprintLibDesc() const override
+    const IO_BASE::IO_FILE_DESC GetLibraryDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "Altium PCB Library or Integrated Library" ),
+        return IO_BASE::IO_FILE_DESC( _HKI( "Altium PCB Library or Integrated Library" ),
                                  { "PcbLib", "IntLib" } );
     }
 
-    PLUGIN_FILE_DESC GetFootprintFileDesc() const override { return GetFootprintLibDesc(); }
-
     bool CanReadBoard( const wxString& aFileName ) const override;
     bool CanReadLibrary( const wxString& aFileName ) const override;
 
diff --git a/pcbnew/pcb_io/altium/pcb_io_solidworks.cpp b/pcbnew/pcb_io/altium/pcb_io_solidworks.cpp
index 696dcbdbad..63f20aac0a 100644
--- a/pcbnew/pcb_io/altium/pcb_io_solidworks.cpp
+++ b/pcbnew/pcb_io/altium/pcb_io_solidworks.cpp
@@ -40,12 +40,6 @@ PCB_IO_SOLIDWORKS::~PCB_IO_SOLIDWORKS()
 }
 
 
-PLUGIN_FILE_DESC PCB_IO_SOLIDWORKS::GetBoardFileDesc() const
-{
-    return PLUGIN_FILE_DESC( _HKI( "Solidworks PCB files" ), { "SWPcbDoc" } );
-}
-
-
 bool PCB_IO_SOLIDWORKS::CanReadBoard( const wxString& aFileName ) const
 {
     if( !PCB_IO::CanReadBoard( aFileName ) )
diff --git a/pcbnew/pcb_io/altium/pcb_io_solidworks.h b/pcbnew/pcb_io/altium/pcb_io_solidworks.h
index 0117d83fc1..f920f944e0 100644
--- a/pcbnew/pcb_io/altium/pcb_io_solidworks.h
+++ b/pcbnew/pcb_io/altium/pcb_io_solidworks.h
@@ -26,7 +26,16 @@
 class PCB_IO_SOLIDWORKS : public PCB_IO
 {
 public:
-    PLUGIN_FILE_DESC GetBoardFileDesc() const override;
+    const IO_BASE::IO_FILE_DESC GetBoardFileDesc() const override
+    {
+        return IO_BASE::IO_FILE_DESC( _HKI( "Solidworks PCB files" ), { "SWPcbDoc" } );
+    }
+
+    const IO_BASE::IO_FILE_DESC GetLibraryDesc() const override
+    {
+        // No library description for this plugin
+        return IO_BASE::IO_FILE_DESC( wxEmptyString, {} );
+    }
 
     bool CanReadBoard( const wxString& aFileName ) const override;
 
diff --git a/pcbnew/pcb_io/cadstar/pcb_io_cadstar_archive.h b/pcbnew/pcb_io/cadstar/pcb_io_cadstar_archive.h
index caca508078..258de19dff 100644
--- a/pcbnew/pcb_io/cadstar/pcb_io_cadstar_archive.h
+++ b/pcbnew/pcb_io/cadstar/pcb_io_cadstar_archive.h
@@ -32,14 +32,12 @@
 class PCB_IO_CADSTAR_ARCHIVE : public PCB_IO, public LAYER_REMAPPABLE_PLUGIN
 {
 public:
-    PLUGIN_FILE_DESC GetBoardFileDesc() const override
+    const IO_BASE::IO_FILE_DESC GetBoardFileDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "CADSTAR PCB Archive files" ), { "cpa" } );
+        return IO_BASE::IO_FILE_DESC( _HKI( "CADSTAR PCB Archive files" ), { "cpa" } );
     }
 
-    PLUGIN_FILE_DESC GetFootprintLibDesc() const override { return GetBoardFileDesc(); }
-
-    PLUGIN_FILE_DESC GetFootprintFileDesc() const override { return GetFootprintLibDesc(); }
+    const IO_BASE::IO_FILE_DESC GetLibraryDesc() const override { return GetBoardFileDesc(); }
 
     bool CanReadBoard( const wxString& aFileName ) const override;
     bool CanReadLibrary( const wxString& aFileName ) const override;
diff --git a/pcbnew/pcb_io/eagle/pcb_io_eagle.h b/pcbnew/pcb_io/eagle/pcb_io_eagle.h
index 7d0866dc5a..bc72c7eb3b 100644
--- a/pcbnew/pcb_io/eagle/pcb_io_eagle.h
+++ b/pcbnew/pcb_io/eagle/pcb_io_eagle.h
@@ -131,18 +131,16 @@ struct ERULES
 class PCB_IO_EAGLE : public PCB_IO, public LAYER_REMAPPABLE_PLUGIN
 {
 public:
-    PLUGIN_FILE_DESC GetBoardFileDesc() const override
+    const IO_BASE::IO_FILE_DESC GetBoardFileDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "Eagle ver. 6.x XML PCB files" ), { "brd" } );
+        return IO_BASE::IO_FILE_DESC( _HKI( "Eagle ver. 6.x XML PCB files" ), { "brd" } );
     }
 
-    PLUGIN_FILE_DESC GetFootprintLibDesc() const override
+    const IO_BASE::IO_FILE_DESC GetLibraryDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "Eagle ver. 6.x XML library files" ), { "lbr" } );
+        return IO_BASE::IO_FILE_DESC( _HKI( "Eagle ver. 6.x XML library files" ), { "lbr" } );
     }
 
-    PLUGIN_FILE_DESC GetFootprintFileDesc() const override { return GetFootprintLibDesc(); }
-
     bool CanReadBoard( const wxString& aFileName ) const override;
     bool CanReadLibrary( const wxString& aFileName ) const override;
     bool CanReadFootprint( const wxString& aFileName ) const override;
diff --git a/pcbnew/pcb_io/easyeda/pcb_io_easyeda_plugin.h b/pcbnew/pcb_io/easyeda/pcb_io_easyeda_plugin.h
index a5f8a01bae..19d61fedba 100644
--- a/pcbnew/pcb_io/easyeda/pcb_io_easyeda_plugin.h
+++ b/pcbnew/pcb_io/easyeda/pcb_io_easyeda_plugin.h
@@ -32,14 +32,14 @@
 class PCB_IO_EASYEDA : public PCB_IO
 {
 public:
-    PLUGIN_FILE_DESC GetBoardFileDesc() const override
+    const IO_BASE::IO_FILE_DESC GetBoardFileDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "EasyEDA (JLCEDA) Std files" ), { "json", "zip" } );
+        return IO_BASE::IO_FILE_DESC( _HKI( "EasyEDA (JLCEDA) Std files" ), { "json", "zip" } );
     }
 
-    PLUGIN_FILE_DESC GetFootprintFileDesc() const override { return GetBoardFileDesc(); }
+    const IO_BASE::IO_FILE_DESC GetLibraryFileDesc() const override { return GetBoardFileDesc(); }
 
-    PLUGIN_FILE_DESC GetFootprintLibDesc() const override { return GetBoardFileDesc(); }
+    const IO_BASE::IO_FILE_DESC GetLibraryDesc() const override { return GetBoardFileDesc(); }
 
     bool CanReadBoard( const wxString& aFileName ) const override;
 
diff --git a/pcbnew/pcb_io/easyedapro/pcb_io_easyedapro.h b/pcbnew/pcb_io/easyedapro/pcb_io_easyedapro.h
index 57efadfe8e..e30deb5063 100644
--- a/pcbnew/pcb_io/easyedapro/pcb_io_easyedapro.h
+++ b/pcbnew/pcb_io/easyedapro/pcb_io_easyedapro.h
@@ -35,21 +35,21 @@
 class PCB_IO_EASYEDAPRO : public PCB_IO, public PROJECT_CHOOSER_PLUGIN
 {
 public:
-    PLUGIN_FILE_DESC GetBoardFileDesc() const override
+    const IO_BASE::IO_FILE_DESC GetBoardFileDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "EasyEDA (JLCEDA) Pro project" ), { "epro", "zip" } );
+        return IO_BASE::IO_FILE_DESC( _HKI( "EasyEDA (JLCEDA) Pro project" ), { "epro", "zip" } );
     }
 
-    PLUGIN_FILE_DESC GetFootprintLibDesc() const override
+    const IO_BASE::IO_FILE_DESC GetLibraryDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "EasyEDA (JLCEDA) Pro project" ),
-                                 { "elibz", "epro", "zip" } );
+        return IO_BASE::IO_FILE_DESC( _HKI( "EasyEDA (JLCEDA) Pro project" ),
+                                      { "elibz", "epro", "zip" } );
     }
 
-    PLUGIN_FILE_DESC GetFootprintFileDesc() const override
+    const IO_BASE::IO_FILE_DESC GetLibraryFileDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "EasyEDA (JLCEDA) Pro files" ),
-                                 { "elibz", "efoo", "epro", "zip" } );
+        return IO_BASE::IO_FILE_DESC( _HKI( "EasyEDA (JLCEDA) Pro files" ),
+                                      { "elibz", "efoo", "epro", "zip" } );
     }
 
     bool CanReadBoard( const wxString& aFileName ) const override;
diff --git a/pcbnew/pcb_io/fabmaster/pcb_io_fabmaster.cpp b/pcbnew/pcb_io/fabmaster/pcb_io_fabmaster.cpp
index 18d197576e..991d2ced11 100644
--- a/pcbnew/pcb_io/fabmaster/pcb_io_fabmaster.cpp
+++ b/pcbnew/pcb_io/fabmaster/pcb_io_fabmaster.cpp
@@ -43,12 +43,6 @@ PCB_IO_FABMASTER::~PCB_IO_FABMASTER()
 }
 
 
-PLUGIN_FILE_DESC PCB_IO_FABMASTER::GetBoardFileDesc() const
-{
-    return PLUGIN_FILE_DESC( _HKI( "Fabmaster PCB files" ), { "txt", "fab" } );
-}
-
-
 BOARD* PCB_IO_FABMASTER::LoadBoard( const wxString& aFileName, BOARD* aAppendToMe,
                                     const STRING_UTF8_MAP* aProperties, PROJECT* aProject,
                                     PROGRESS_REPORTER* aProgressReporter )
diff --git a/pcbnew/pcb_io/fabmaster/pcb_io_fabmaster.h b/pcbnew/pcb_io/fabmaster/pcb_io_fabmaster.h
index b356d76ca0..117af297db 100644
--- a/pcbnew/pcb_io/fabmaster/pcb_io_fabmaster.h
+++ b/pcbnew/pcb_io/fabmaster/pcb_io_fabmaster.h
@@ -33,7 +33,16 @@
 class PCB_IO_FABMASTER : public PCB_IO
 {
 public:
-    PLUGIN_FILE_DESC GetBoardFileDesc() const override;
+    const IO_BASE::IO_FILE_DESC GetBoardFileDesc() const override
+    {
+       return IO_BASE::IO_FILE_DESC( _HKI( "Fabmaster PCB files" ), { "txt", "fab" } );
+    }
+
+    const IO_BASE::IO_FILE_DESC GetLibraryDesc() const override
+    {
+        // No library description for this plugin
+        return IO_BASE::IO_FILE_DESC( wxEmptyString, {} );
+    }
 
     BOARD* LoadBoard( const wxString& aFileName, BOARD* aAppendToMe,
                       const STRING_UTF8_MAP* aProperties = nullptr, PROJECT* aProject = nullptr,
diff --git a/pcbnew/pcb_io/geda/pcb_io_geda.h b/pcbnew/pcb_io/geda/pcb_io_geda.h
index 0a71e88c06..5d36dec721 100644
--- a/pcbnew/pcb_io/geda/pcb_io_geda.h
+++ b/pcbnew/pcb_io/geda/pcb_io_geda.h
@@ -47,15 +47,15 @@ class GPCB_FPL_CACHE;
 class PCB_IO_GEDA : public PCB_IO
 {
 public:
-    PLUGIN_FILE_DESC GetFootprintFileDesc() const override
+    const IO_BASE::IO_FILE_DESC GetLibraryFileDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "gEDA PCB footprint file" ), { "fp" } );
+        return IO_BASE::IO_FILE_DESC( _HKI( "gEDA PCB footprint file" ), { "fp" } );
     }
 
-    PLUGIN_FILE_DESC GetFootprintLibDesc() const override
+    const IO_BASE::IO_FILE_DESC GetLibraryDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "gEDA PCB footprint library directory" ), {}, { "fp" },
-                                 false );
+        return IO_BASE::IO_FILE_DESC( _HKI( "gEDA PCB footprint library directory" ), {}, { "fp" },
+                                      false );
     }
 
     FOOTPRINT* ImportFootprint( const wxString& aFootprintPath, wxString& aFootprintNameOut,
diff --git a/pcbnew/pcb_io/ipc2581/pcb_io_ipc2581.h b/pcbnew/pcb_io/ipc2581/pcb_io_ipc2581.h
index 6802997d1e..ca927acf90 100644
--- a/pcbnew/pcb_io/ipc2581/pcb_io_ipc2581.h
+++ b/pcbnew/pcb_io/ipc2581/pcb_io_ipc2581.h
@@ -85,10 +85,17 @@ public:
                 const STRING_UTF8_MAP* aProperties = nullptr,
                 PROGRESS_REPORTER*     aProgressReporter = nullptr ) override;
 
-    PLUGIN_FILE_DESC GetBoardFileDesc() const override
+    const IO_BASE::IO_FILE_DESC GetBoardFileDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "IPC-2581 Production File" ), { "xml" } );
+        return IO_BASE::IO_FILE_DESC( _HKI( "IPC-2581 Production File" ), { "xml" } );
     }
+
+    const IO_BASE::IO_FILE_DESC GetLibraryDesc() const override
+    {
+        // No library description for this plugin
+        return IO_BASE::IO_FILE_DESC( wxEmptyString, {} );
+    }
+
     std::vector<FOOTPRINT*> GetImportedCachedLibraryFootprints() override;
 
     long long GetLibraryTimestamp( const wxString& aLibraryPath ) const override
diff --git a/pcbnew/pcb_io/kicad_legacy/pcb_io_kicad_legacy.h b/pcbnew/pcb_io/kicad_legacy/pcb_io_kicad_legacy.h
index 1a376f1c4e..bbf87a2992 100644
--- a/pcbnew/pcb_io/kicad_legacy/pcb_io_kicad_legacy.h
+++ b/pcbnew/pcb_io/kicad_legacy/pcb_io_kicad_legacy.h
@@ -66,18 +66,16 @@ public:
     PCB_IO_KICAD_LEGACY();
     ~PCB_IO_KICAD_LEGACY();
 
-    PLUGIN_FILE_DESC GetBoardFileDesc() const override
+    const IO_BASE::IO_FILE_DESC GetBoardFileDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "Eagle ver. 6.x XML PCB files" ), { "brd" } );
+        return IO_BASE::IO_FILE_DESC( _HKI( "Eagle ver. 6.x XML PCB files" ), { "brd" } );
     }
 
-    PLUGIN_FILE_DESC GetFootprintLibDesc() const override
+    const IO_BASE::IO_FILE_DESC GetLibraryDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "Legacy footprint library files" ), { "mod", "emp" } );
+        return IO_BASE::IO_FILE_DESC( _HKI( "Legacy footprint library files" ), { "mod", "emp" } );
     }
 
-    PLUGIN_FILE_DESC GetFootprintFileDesc() const override { return GetFootprintLibDesc(); }
-
     bool CanReadBoard( const wxString& aFileName ) const override;
     bool CanReadFootprint( const wxString& aFileName ) const override;
 
diff --git a/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.h b/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.h
index 28de8da9f9..921e391fa0 100644
--- a/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.h
+++ b/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.h
@@ -277,23 +277,23 @@ public:
 class PCB_IO_KICAD_SEXPR : public PCB_IO
 {
 public:
-    PLUGIN_FILE_DESC GetBoardFileDesc() const override
+    const IO_BASE::IO_FILE_DESC GetBoardFileDesc() const override
     {
         // Would have used wildcards_and_files_ext.cpp's KiCadPcbFileExtension,
         // but to be pure, a plugin should not assume that it will always be linked
         // with the core of the Pcbnew code. (Might someday be a DLL/DSO.)  Besides,
         // file extension policy should be controlled by the plugin.
-        return PLUGIN_FILE_DESC( _HKI( "KiCad printed circuit board files" ), { "kicad_pcb" } );
+        return IO_BASE::IO_FILE_DESC( _HKI( "KiCad printed circuit board files" ), { "kicad_pcb" } );
     }
 
-    PLUGIN_FILE_DESC GetFootprintFileDesc() const override
+    const IO_BASE::IO_FILE_DESC GetLibraryFileDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "KiCad footprint file" ), { "kicad_mod" } );
+        return IO_BASE::IO_FILE_DESC( _HKI( "KiCad footprint file" ), { "kicad_mod" } );
     }
 
-    PLUGIN_FILE_DESC GetFootprintLibDesc() const override
+    const IO_BASE::IO_FILE_DESC GetLibraryDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "KiCad footprint files" ), {}, { "kicad_mod" }, false );
+        return IO_BASE::IO_FILE_DESC( _HKI( "KiCad footprint files" ), {}, { "kicad_mod" }, false );
     }
 
     void SetQueryUserCallback( std::function<bool( wxString aTitle, int aIcon, wxString aMessage,
diff --git a/pcbnew/pcb_io/pcad/pcb_io_pcad.h b/pcbnew/pcb_io/pcad/pcb_io_pcad.h
index 74bdb99e16..84c9959c31 100644
--- a/pcbnew/pcb_io/pcad/pcb_io_pcad.h
+++ b/pcbnew/pcb_io/pcad/pcb_io_pcad.h
@@ -39,9 +39,15 @@ public:
     PCB_IO_PCAD();
     ~PCB_IO_PCAD();
 
-    PLUGIN_FILE_DESC GetBoardFileDesc() const override
+    const IO_BASE::IO_FILE_DESC GetBoardFileDesc() const override
     {
-        return PLUGIN_FILE_DESC( _HKI( "P-Cad 200x ASCII PCB files" ), { "pcb" } );
+        return IO_BASE::IO_FILE_DESC( _HKI( "P-Cad 200x ASCII PCB files" ), { "pcb" } );
+    }
+
+    const IO_BASE::IO_FILE_DESC GetLibraryDesc() const override
+    {
+        // No library description for this plugin
+        return IO_BASE::IO_FILE_DESC( wxEmptyString, {} );
     }
 
     bool CanReadBoard( const wxString& aFileName ) const override;
diff --git a/pcbnew/pcb_io/pcb_io.cpp b/pcbnew/pcb_io/pcb_io.cpp
index 84d468a467..be6c42f5a8 100644
--- a/pcbnew/pcb_io/pcb_io.cpp
+++ b/pcbnew/pcb_io/pcb_io.cpp
@@ -40,24 +40,6 @@
                                       wxString::FromUTF8( aCaller ) ) );
 
 
-PLUGIN_FILE_DESC PCB_IO::GetBoardFileDesc() const
-{
-    return PLUGIN_FILE_DESC( wxEmptyString, {} );
-}
-
-
-PLUGIN_FILE_DESC PCB_IO::GetFootprintFileDesc() const
-{
-    return PLUGIN_FILE_DESC( wxEmptyString, {} );
-}
-
-
-PLUGIN_FILE_DESC PCB_IO::GetFootprintLibDesc() const
-{
-    return PLUGIN_FILE_DESC( wxEmptyString, {} );
-}
-
-
 bool PCB_IO::CanReadBoard( const wxString& aFileName ) const
 {
     const std::vector<std::string>& exts = GetBoardFileDesc().m_FileExtensions;
@@ -76,7 +58,7 @@ bool PCB_IO::CanReadBoard( const wxString& aFileName ) const
 
 bool PCB_IO::CanReadFootprint( const wxString& aFileName ) const
 {
-    const std::vector<std::string>& exts = GetFootprintFileDesc().m_FileExtensions;
+    const std::vector<std::string>& exts = GetLibraryFileDesc().m_FileExtensions;
 
     wxString fileExt = wxFileName( aFileName ).GetExt().MakeLower();
 
@@ -92,7 +74,7 @@ bool PCB_IO::CanReadFootprint( const wxString& aFileName ) const
 
 bool PCB_IO::CanReadLibrary( const wxString& aFileName ) const
 {
-    const PLUGIN_FILE_DESC& desc = GetFootprintLibDesc();
+    const IO_BASE::IO_FILE_DESC& desc = GetLibraryDesc();
 
     if( desc.m_IsFile )
     {
diff --git a/pcbnew/pcb_io/pcb_io.h b/pcbnew/pcb_io/pcb_io.h
index a731b98577..4e362c7ad7 100644
--- a/pcbnew/pcb_io/pcb_io.h
+++ b/pcbnew/pcb_io/pcb_io.h
@@ -26,7 +26,6 @@
 #define PCB_IO_H_
 
 #include <io/io_base.h>
-#include <plugin_file_desc.h>
 #include <pcb_io/pcb_io_mgr.h>
 
 #include <cstdint>
@@ -75,17 +74,11 @@ public:
     /**
      * Returns board file description for the PCB_IO.
      */
-    virtual PLUGIN_FILE_DESC GetBoardFileDesc() const;
+    virtual const IO_BASE::IO_FILE_DESC GetBoardFileDesc() const
+    {
+        return IO_BASE::IO_FILE_DESC( wxEmptyString, {} );
+    }
 
-    /**
-     * Returns footprint file description for the PCB_IO.
-     */
-    virtual PLUGIN_FILE_DESC GetFootprintFileDesc() const;
-
-    /**
-     * Returns footprint library description for the PCB_IO.
-     */
-    virtual PLUGIN_FILE_DESC GetFootprintLibDesc() const;
 
     /**
      * Checks if this PCB_IO can read the specified board file.
diff --git a/pcbnew/pcb_io/pcb_io_mgr.h b/pcbnew/pcb_io/pcb_io_mgr.h
index c3dc4c88e5..b5c2e4d349 100644
--- a/pcbnew/pcb_io/pcb_io_mgr.h
+++ b/pcbnew/pcb_io/pcb_io_mgr.h
@@ -30,7 +30,7 @@
 #include <vector>
 #include <wx/arrstr.h>
 #include <i18n_utility.h>
-#include <plugin_file_desc.h>
+#include <io/io_base.h>
 
 class BOARD;
 class PCB_IO;